mirror of https://github.com/mchr3k/org.intrace
- Add unit tests
- Fix array argument passing - Upgrade to asm 3.2 - Checkin modified asm library with fix for synthetic bit handling
This commit is contained in:
parent
37e14ce43a
commit
e9760a29c2
|
|
@ -1,3 +1,6 @@
|
|||
.metadata/
|
||||
*/bin/*
|
||||
*/built/*
|
||||
*/built/*
|
||||
*/genbin/*
|
||||
asm3.2_*
|
||||
libsrc*
|
||||
Binary file not shown.
|
|
@ -0,0 +1,161 @@
|
|||
package org.test.intrace;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jdi.Bootstrap;
|
||||
import com.sun.jdi.Field;
|
||||
import com.sun.jdi.IncompatibleThreadStateException;
|
||||
import com.sun.jdi.LocalVariable;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.StackFrame;
|
||||
import com.sun.jdi.ThreadReference;
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
import com.sun.jdi.VirtualMachineManager;
|
||||
import com.sun.jdi.connect.AttachingConnector;
|
||||
import com.sun.jdi.connect.Connector.Argument;
|
||||
|
||||
public class DebugTest
|
||||
{
|
||||
private static final String field = "Foo";
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
int ii = 10;
|
||||
threadID(Thread.currentThread().getId());
|
||||
System.out.println(ii);
|
||||
System.out.println(field);
|
||||
}
|
||||
|
||||
private static void threadID(long id)
|
||||
{
|
||||
Thread dbg = new Thread(new Debugger(Thread.currentThread().getId(),
|
||||
Thread.currentThread().getName()));
|
||||
dbg.start();
|
||||
try
|
||||
{
|
||||
dbg.join();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// Throw away
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Debugger implements Runnable
|
||||
{
|
||||
private final String name;
|
||||
private final long id;
|
||||
|
||||
public Debugger(long id, String name)
|
||||
{
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
|
||||
List<AttachingConnector> connectors = vmm.attachingConnectors();
|
||||
for (AttachingConnector connector : connectors)
|
||||
{
|
||||
if (connector.name().contains("SocketAttach"))
|
||||
{
|
||||
try
|
||||
{
|
||||
Map<String, Argument> args = connector.defaultArguments();
|
||||
args.get("hostname").setValue("localhost");
|
||||
args.get("port").setValue("8000");
|
||||
VirtualMachine vm = connector.attach(args);
|
||||
useVM(vm);
|
||||
vm.dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void useVM(VirtualMachine vm)
|
||||
{
|
||||
List<ThreadReference> threads = vm.allThreads();
|
||||
for (ThreadReference thread : threads)
|
||||
{
|
||||
if (name.equals(thread.name()))
|
||||
{
|
||||
thread.suspend();
|
||||
try
|
||||
{
|
||||
int ii = 0;
|
||||
for (StackFrame frame : thread.frames())
|
||||
{
|
||||
if (matchingFrame(frame))
|
||||
{
|
||||
StackFrame callingFrame = thread.frame(ii + 1);
|
||||
useFrame(callingFrame);
|
||||
}
|
||||
ii++;
|
||||
}
|
||||
thread.resume();
|
||||
}
|
||||
catch (IncompatibleThreadStateException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matchingFrame(StackFrame frame)
|
||||
{
|
||||
if ("threadID".equals(frame.location().method().name())
|
||||
&& (frame.getArgumentValues().size() == 1)
|
||||
&& (frame.getArgumentValues().get(0).toString()
|
||||
.equals(Long
|
||||
.toString(id))))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void useFrame(StackFrame frame)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("Fields:");
|
||||
ReferenceType type = frame.location().declaringType();
|
||||
for (Field field : type.fields())
|
||||
{
|
||||
System.out.println(field.name() + " => " + type.getValue(field));
|
||||
}
|
||||
System.out.println("\nLocal Variables:");
|
||||
for (LocalVariable variable : frame.visibleVariables())
|
||||
{
|
||||
if (!variable.isArgument())
|
||||
{
|
||||
System.out.println(variable.name() + " => "
|
||||
+ frame.getValue(variable));
|
||||
}
|
||||
}
|
||||
System.out.println("\nDone\n");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package org.test.intrace;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TraceExample
|
||||
{
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
otherMain("123");
|
||||
}
|
||||
|
||||
public static void otherMain(String arg) throws Exception
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
InnerTest.foo();
|
||||
workMethod("foobar");
|
||||
}
|
||||
}
|
||||
|
||||
private static void workMethod(String foo)
|
||||
{
|
||||
long currentTime = System.currentTimeMillis();
|
||||
System.setProperty("a",foo);
|
||||
intArrayMethod(new int[] {1,2,3});
|
||||
if ((currentTime % 2) == 0)
|
||||
{
|
||||
System.setProperty("a","Even time");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.setProperty("a","Odd time");
|
||||
}
|
||||
}
|
||||
|
||||
private static void intArrayMethod(int[] intArg)
|
||||
{
|
||||
System.setProperty("a",Arrays.toString(intArg));
|
||||
}
|
||||
|
||||
private static class InnerTest
|
||||
{
|
||||
private static void foo()
|
||||
{
|
||||
System.setProperty("a","bar");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,9 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="testsrc"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="lib" path="lib/asm-2.2.3.jar"/>
|
||||
<classpathentry kind="lib" path="lib/asm-commons-2.2.3.jar"/>
|
||||
<classpathentry kind="con" path="SWT_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
|
||||
<classpathentry kind="lib" path="lib/org.eclipse.swt.win32.win32.x86_3.5.2.v3557f.jar"/>
|
||||
<classpathentry kind="lib" path="lib/easymockclassextension-2.5.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/easymock-2.5.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/cglib-nodep-2.2.jar"/>
|
||||
<classpathentry kind="lib" path="genbin"/>
|
||||
<classpathentry kind="lib" path="lib/asm-3.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/asm-commons-3.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/asm-util-3.2.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
|
|||
|
|
@ -22,15 +22,21 @@
|
|||
|
||||
<delete dir="./lib/libclasses" includes="**/*" />
|
||||
<mkdir dir="./lib/libclasses" />
|
||||
<unzip src="./lib/asm-2.2.3.jar" dest="./lib/libclasses">
|
||||
<unzip src="./lib/asm-3.2.jar" dest="./lib/libclasses">
|
||||
<patternset>
|
||||
<include name="**/*.class" />
|
||||
<exclude name="META-INF" />
|
||||
</patternset>
|
||||
</unzip>
|
||||
<unzip src="./lib/asm-commons-2.2.3.jar" dest="./lib/libclasses">
|
||||
<unzip src="./lib/asm-commons-3.2.jar" dest="./lib/libclasses">
|
||||
<patternset>
|
||||
<include name="**/EmptyVisitor.class" />
|
||||
<include name="**/*.class" />
|
||||
<exclude name="META-INF" />
|
||||
</patternset>
|
||||
</unzip>
|
||||
<unzip src="./lib/asm-util-3.2.jar" dest="./lib/libclasses">
|
||||
<patternset>
|
||||
<include name="**/*.class" />
|
||||
<exclude name="META-INF" />
|
||||
</patternset>
|
||||
</unzip>
|
||||
|
|
@ -45,6 +51,10 @@
|
|||
<fileset dir="./lib/libclasses" includes="**/*.class" />
|
||||
</jar>
|
||||
|
||||
<!-- Test Trace Agent -->
|
||||
<jar destfile="./built/traceagent_test.jar" compress="false" manifest="conf/META-INF/MANIFEST.MF">
|
||||
</jar>
|
||||
|
||||
<!-- CUI Trace Client -->
|
||||
<jar destfile="./built/cuitraceclient.jar" compress="false">
|
||||
<manifest>
|
||||
|
|
@ -70,6 +80,6 @@
|
|||
</target>
|
||||
|
||||
<target name="deploy" description="Copy agent jar to another project">
|
||||
<copy file="./built/traceagent.jar" tofile="../TestProject/lib/traceagent.jar" overwrite="true" />
|
||||
<copy file="./built/traceagent.jar" tofile="../org.intrace.test/lib/traceagent.jar" overwrite="true" />
|
||||
</target>
|
||||
</project>
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -7,17 +7,15 @@ import java.util.regex.Pattern;
|
|||
import org.intrace.shared.AgentConfigConstants;
|
||||
|
||||
/**
|
||||
* Args Format:
|
||||
* "[arg1[arg2[arg3"
|
||||
* Args Format: "[arg1[arg2[arg3"
|
||||
*
|
||||
* where argx is of the form
|
||||
* value-parameter
|
||||
* where argx is of the form value-parameter
|
||||
*/
|
||||
public class AgentSettings
|
||||
{
|
||||
private Pattern classRegex = Pattern.compile(".*");
|
||||
private boolean instruEnabled = false;
|
||||
private boolean saveTracedClassfiles = false;
|
||||
private boolean saveTracedClassfiles = true;
|
||||
private boolean verboseMode = false;
|
||||
private boolean allowJarsToBeTraced = false;
|
||||
|
||||
|
|
@ -50,31 +48,41 @@ public class AgentSettings
|
|||
{
|
||||
verboseMode = true;
|
||||
}
|
||||
else if (arg.toLowerCase().equals(AgentConfigConstants.VERBOSE_MODE + "false"))
|
||||
else if (arg.toLowerCase().equals(
|
||||
AgentConfigConstants.VERBOSE_MODE
|
||||
+ "false"))
|
||||
{
|
||||
verboseMode = false;
|
||||
}
|
||||
else if (arg.toLowerCase().equals(AgentConfigConstants.INSTRU_ENABLED + "true"))
|
||||
else if (arg.toLowerCase().equals(
|
||||
AgentConfigConstants.INSTRU_ENABLED
|
||||
+ "true"))
|
||||
{
|
||||
instruEnabled = true;
|
||||
}
|
||||
else if (arg.toLowerCase().equals(AgentConfigConstants.INSTRU_ENABLED + "false"))
|
||||
else if (arg.toLowerCase().equals(
|
||||
AgentConfigConstants.INSTRU_ENABLED
|
||||
+ "false"))
|
||||
{
|
||||
instruEnabled = false;
|
||||
}
|
||||
else if (arg.toLowerCase().equals(AgentConfigConstants.SAVE_TRACED_CLASSFILES + "true"))
|
||||
else if (arg.toLowerCase()
|
||||
.equals(AgentConfigConstants.SAVE_TRACED_CLASSFILES + "true"))
|
||||
{
|
||||
saveTracedClassfiles = true;
|
||||
}
|
||||
else if (arg.toLowerCase().equals(AgentConfigConstants.SAVE_TRACED_CLASSFILES + "false"))
|
||||
else if (arg.toLowerCase()
|
||||
.equals(AgentConfigConstants.SAVE_TRACED_CLASSFILES + "false"))
|
||||
{
|
||||
saveTracedClassfiles = false;
|
||||
}
|
||||
else if (arg.toLowerCase().equals(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED + "true"))
|
||||
else if (arg.toLowerCase()
|
||||
.equals(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED + "true"))
|
||||
{
|
||||
allowJarsToBeTraced = true;
|
||||
}
|
||||
else if (arg.toLowerCase().equals(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED + "false"))
|
||||
else if (arg.toLowerCase()
|
||||
.equals(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED + "false"))
|
||||
{
|
||||
allowJarsToBeTraced = false;
|
||||
}
|
||||
|
|
@ -116,19 +124,25 @@ public class AgentSettings
|
|||
String currentSettings = "";
|
||||
currentSettings += "Class Regex : " + classRegex + "\n";
|
||||
currentSettings += "Tracing Enabled : " + instruEnabled + "\n";
|
||||
currentSettings += "Save Traced Class Files : " + saveTracedClassfiles + "\n";
|
||||
currentSettings += "Trace Classes in JAR Files : " + allowJarsToBeTraced + "\n";
|
||||
currentSettings += "Save Traced Class Files : " + saveTracedClassfiles
|
||||
+ "\n";
|
||||
currentSettings += "Trace Classes in JAR Files : " + allowJarsToBeTraced
|
||||
+ "\n";
|
||||
return currentSettings;
|
||||
}
|
||||
|
||||
public Map<String,String> getSettingsMap()
|
||||
public Map<String, String> getSettingsMap()
|
||||
{
|
||||
Map<String,String> settingsMap = new HashMap<String, String>();
|
||||
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));
|
||||
settingsMap.put(AgentConfigConstants.SAVE_TRACED_CLASSFILES, Boolean.toString(saveTracedClassfiles));
|
||||
Map<String, String> settingsMap = new HashMap<String, String>();
|
||||
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));
|
||||
settingsMap.put(AgentConfigConstants.SAVE_TRACED_CLASSFILES,
|
||||
Boolean.toString(saveTracedClassfiles));
|
||||
return settingsMap;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package org.intrace.agent;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.GOTO;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
|
@ -51,15 +49,15 @@ import org.objectweb.asm.commons.EmptyVisitor;
|
|||
*
|
||||
* <h3>Line 5:</h3>
|
||||
* <ul>
|
||||
* <li>{@link ClassAnalysis#visitLineNumber(int, Label)} is called and
|
||||
* we record a mapping from label1 to line 5.
|
||||
* <li>{@link ClassAnalysis#visitLineNumber(int, Label)} is called and we record
|
||||
* a mapping from label1 to line 5.
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Line 8:</h3>
|
||||
* <ul>
|
||||
* <li>{@link ClassAnalysis#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.
|
||||
* <li>{@link ClassAnalysis#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.
|
||||
* </ul>
|
||||
*
|
||||
* <h1>Method Entry Line</h1> This analysis records the first source line of a
|
||||
|
|
@ -104,25 +102,19 @@ public class ClassAnalysis extends EmptyVisitor
|
|||
@Override
|
||||
public void visitJumpInsn(int xiOpCode, Label xiBranchLabel)
|
||||
{
|
||||
if (xiOpCode == GOTO)
|
||||
Integer lineNo = currentMethod_labelLineNos.get(xiBranchLabel);
|
||||
if (lineNo != null)
|
||||
{
|
||||
Integer lineNo = currentMethod_labelLineNos.get(xiBranchLabel);
|
||||
if (lineNo != null)
|
||||
{
|
||||
currentMethod_reverseGOTOLines.add(lineNo);
|
||||
}
|
||||
currentMethod_reverseGOTOLines.add(lineNo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd()
|
||||
{
|
||||
if (currentMethod_sig != null)
|
||||
{
|
||||
methodReverseGOTOLines.put(currentMethod_sig,
|
||||
currentMethod_reverseGOTOLines);
|
||||
currentMethod_sig = null;
|
||||
currentMethod_reverseGOTOLines = new HashSet<Integer>();
|
||||
}
|
||||
methodReverseGOTOLines.put(currentMethod_sig,
|
||||
currentMethod_reverseGOTOLines);
|
||||
currentMethod_sig = null;
|
||||
currentMethod_reverseGOTOLines = new HashSet<Integer>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,10 +69,12 @@ public class ClassTransformer implements ClassFileTransformer
|
|||
{
|
||||
ClassReader cr = new ClassReader(classfileBuffer);
|
||||
ClassAnalysis analysis = new ClassAnalysis();
|
||||
cr.accept(analysis, false);
|
||||
cr.accept(analysis, 0);
|
||||
|
||||
InstrumentedClassWriter writer = new InstrumentedClassWriter(xiClassName,
|
||||
cr, analysis);
|
||||
cr.accept(writer, false);
|
||||
cr.accept(writer, 0);
|
||||
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
|
|
@ -93,6 +95,10 @@ public class ClassTransformer implements ClassFileTransformer
|
|||
{
|
||||
if (modifiedClasses.contains(loadedClass.getName()))
|
||||
{
|
||||
if (settings.isVerboseMode())
|
||||
{
|
||||
System.out.println("Retransform class: " + loadedClass.getName());
|
||||
}
|
||||
inst.retransformClasses(loadedClass);
|
||||
}
|
||||
}
|
||||
|
|
@ -136,7 +142,8 @@ public class ClassTransformer implements ClassFileTransformer
|
|||
{
|
||||
if (settings.isVerboseMode())
|
||||
{
|
||||
System.out.println("Ignoring class in gb.instrument package: "
|
||||
System.out
|
||||
.println("Ignoring class in org.intrace or org.objectweb.asm package: "
|
||||
+ className);
|
||||
}
|
||||
return false;
|
||||
|
|
@ -214,37 +221,25 @@ public class ClassTransformer implements ClassFileTransformer
|
|||
System.out.println("!! Instrumenting class: " + className);
|
||||
}
|
||||
|
||||
byte[] newBytes = getInstrumentedClassBytes(className, originalClassfile);
|
||||
byte[] newBytes;
|
||||
try
|
||||
{
|
||||
newBytes = getInstrumentedClassBytes(className, originalClassfile);
|
||||
}
|
||||
catch (RuntimeException th)
|
||||
{
|
||||
th.printStackTrace();
|
||||
throw th;
|
||||
}
|
||||
catch (Error th)
|
||||
{
|
||||
th.printStackTrace();
|
||||
throw th;
|
||||
}
|
||||
|
||||
if (settings.saveTracedClassfiles())
|
||||
{
|
||||
try
|
||||
{
|
||||
File classOut = new File("./genbin/" + internalClassName
|
||||
+ "_gen.class");
|
||||
File parentDir = classOut.getParentFile();
|
||||
boolean dirExists = parentDir.exists();
|
||||
if (!dirExists)
|
||||
{
|
||||
dirExists = parentDir.mkdirs();
|
||||
}
|
||||
if (dirExists)
|
||||
{
|
||||
OutputStream out = new FileOutputStream(classOut);
|
||||
out.write(newBytes);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Can't create directory " + parentDir
|
||||
+ " for saving traced classfiles.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
writeClassBytes(newBytes, internalClassName + "_gen.class");
|
||||
}
|
||||
|
||||
modifiedClasses.add(className);
|
||||
|
|
@ -257,6 +252,36 @@ public class ClassTransformer implements ClassFileTransformer
|
|||
}
|
||||
}
|
||||
|
||||
private void writeClassBytes(byte[] newBytes, String className)
|
||||
{
|
||||
try
|
||||
{
|
||||
File classOut = new File("./genbin/" + className);
|
||||
File parentDir = classOut.getParentFile();
|
||||
boolean dirExists = parentDir.exists();
|
||||
if (!dirExists)
|
||||
{
|
||||
dirExists = parentDir.mkdirs();
|
||||
}
|
||||
if (dirExists)
|
||||
{
|
||||
OutputStream out = new FileOutputStream(classOut);
|
||||
out.write(newBytes);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println("Can't create directory " + parentDir
|
||||
+ " for saving traced classfiles.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consider loaded classes for transformation. Any of the following reasons
|
||||
* would prevent a loaded class from being eligible for instrumentation.
|
||||
|
|
@ -304,6 +329,7 @@ public class ClassTransformer implements ClassFileTransformer
|
|||
{
|
||||
try
|
||||
{
|
||||
// System.out.println("ReTransform: " + loadedClass.getName());
|
||||
inst.retransformClasses(loadedClass);
|
||||
}
|
||||
catch (Throwable e)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package org.intrace.agent;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
|
||||
import static org.objectweb.asm.Opcodes.RETURN;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.intrace.output.AgentHelper;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Label;
|
||||
|
|
@ -21,8 +23,9 @@ import org.objectweb.asm.Type;
|
|||
*/
|
||||
public class InstrumentedClassWriter extends ClassWriter
|
||||
{
|
||||
private final String mClassName;
|
||||
private final String className;
|
||||
private final ClassAnalysis analysis;
|
||||
private int methodNum = 1;
|
||||
|
||||
/**
|
||||
* cTor
|
||||
|
|
@ -34,8 +37,8 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
public InstrumentedClassWriter(String xiClassName, ClassReader xiReader,
|
||||
ClassAnalysis xiAnalysis)
|
||||
{
|
||||
super(xiReader, true);
|
||||
mClassName = xiClassName;
|
||||
super(xiReader, COMPUTE_MAXS);
|
||||
className = xiClassName;
|
||||
analysis = xiAnalysis;
|
||||
}
|
||||
|
||||
|
|
@ -53,14 +56,10 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
Set<Integer> branchTraceLines = analysis.methodReverseGOTOLines.get(name
|
||||
+ desc);
|
||||
Integer entryLine = analysis.methodEntryLines.get(name + desc);
|
||||
if (branchTraceLines == null)
|
||||
{
|
||||
branchTraceLines = new HashSet<Integer>();
|
||||
}
|
||||
|
||||
// Transform the method
|
||||
return new InstrumentedMethodWriter(mv, name, desc, branchTraceLines,
|
||||
entryLine);
|
||||
return new InstrumentedMethodWriter(mv, access, name, desc,
|
||||
branchTraceLines, entryLine);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -73,6 +72,9 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
// Final method fields
|
||||
private final String methodName;
|
||||
private final String methodDescriptor;
|
||||
private final int methodAccess;
|
||||
private final Map<Label, Integer> labelLineNos = new HashMap<Label, Integer>();
|
||||
private final Set<Label> traceLabels = new HashSet<Label>();
|
||||
|
||||
// Analysis data
|
||||
private final Set<Integer> reverseGOTOLines;
|
||||
|
|
@ -80,27 +82,43 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
|
||||
// State
|
||||
private boolean writeTraceLine = false;
|
||||
private CTorEntryState ctorEntryState = CTorEntryState.NORMALMETHOD;
|
||||
private int lineNumber = -1;
|
||||
private int numBranchesOnLine = 0;
|
||||
private TernaryState ternState = TernaryState.BASE;
|
||||
|
||||
/**
|
||||
* cTor
|
||||
*
|
||||
* @param xiMethodVisitor
|
||||
* @param access
|
||||
* @param xiClassName
|
||||
* @param xiMethodName
|
||||
* @param xiDesc
|
||||
* @param xiBranchTraceLines
|
||||
* @param entryLine
|
||||
*/
|
||||
public InstrumentedMethodWriter(MethodVisitor xiMethodVisitor,
|
||||
public InstrumentedMethodWriter(MethodVisitor xiMethodVisitor, int access,
|
||||
String xiMethodName, String xiDesc, Set<Integer> xiBranchTraceLines,
|
||||
Integer xiEntryLine)
|
||||
{
|
||||
super(xiMethodVisitor);
|
||||
methodAccess = access;
|
||||
methodName = xiMethodName;
|
||||
methodDescriptor = xiDesc;
|
||||
reverseGOTOLines = xiBranchTraceLines;
|
||||
entryLine = xiEntryLine;
|
||||
if (methodName.equals("<init>"))
|
||||
{
|
||||
ctorEntryState = CTorEntryState.ISCTOR;
|
||||
}
|
||||
}
|
||||
|
||||
// MCHR: Need to preserve Synthetic attribute
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr)
|
||||
{
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -108,11 +126,22 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
*/
|
||||
@Override
|
||||
public void visitCode()
|
||||
{
|
||||
methodNum++;
|
||||
if (ctorEntryState != CTorEntryState.ISCTOR)
|
||||
{
|
||||
addEntryCalls();
|
||||
}
|
||||
// For Constructors we add the entry calls after the first invokeSpecial
|
||||
// which calls into the superclass constructor.
|
||||
super.visitCode();
|
||||
}
|
||||
|
||||
private void addEntryCalls()
|
||||
{
|
||||
generateCallToAgentHelper(InstrumentationType.ENTER,
|
||||
((entryLine != null ? entryLine : -1)));
|
||||
traceMethodArgs();
|
||||
super.visitCode();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -121,29 +150,81 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
private void traceMethodArgs()
|
||||
{
|
||||
Type[] argTypes = Type.getArgumentTypes(methodDescriptor);
|
||||
boolean isStaticAccess = ((methodAccess & Opcodes.ACC_STATIC) > 0);
|
||||
int offset = (isStaticAccess ? 0 : 1);
|
||||
|
||||
for (int ii = 0; ii < argTypes.length; ii++)
|
||||
{
|
||||
String typeDescriptor = argTypes[ii].getDescriptor();
|
||||
|
||||
int varslot = ii + offset;
|
||||
int opcode = Opcodes.ILOAD;
|
||||
if (argTypes[ii].getSort() == Type.OBJECT)
|
||||
{
|
||||
typeDescriptor = "Ljava/lang/Object;";
|
||||
opcode = Opcodes.ALOAD;
|
||||
}
|
||||
else if ((argTypes[ii].getSort() == Type.ARRAY)
|
||||
&& (argTypes[ii].getDescriptor().startsWith("[[")))
|
||||
{
|
||||
// All multidimensional arrays are handled by the object array
|
||||
// function
|
||||
typeDescriptor = "[Ljava/lang/Object;";
|
||||
}
|
||||
else if ((argTypes[ii].getSort() == Type.ARRAY)
|
||||
&& (argTypes[ii].getDescriptor().startsWith("[L")))
|
||||
{
|
||||
// All object arrays are cast to the object supertype
|
||||
typeDescriptor = "[Ljava/lang/Object;";
|
||||
}
|
||||
else if (argTypes[ii].getSort() == Type.LONG)
|
||||
{
|
||||
opcode = Opcodes.LLOAD;
|
||||
offset++;
|
||||
}
|
||||
else if (argTypes[ii].getSort() == Type.FLOAT)
|
||||
{
|
||||
opcode = Opcodes.FLOAD;
|
||||
}
|
||||
else if (argTypes[ii].getSort() == Type.DOUBLE)
|
||||
{
|
||||
opcode = Opcodes.DLOAD;
|
||||
offset++;
|
||||
}
|
||||
|
||||
mv.visitLdcInsn(mClassName);
|
||||
if (argTypes[ii].getSort() == Type.ARRAY)
|
||||
{
|
||||
opcode = Opcodes.ALOAD;
|
||||
}
|
||||
|
||||
mv.visitLdcInsn(className);
|
||||
mv.visitLdcInsn(methodName);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, ii);
|
||||
mv.visitVarInsn(opcode, varslot);
|
||||
mv.visitMethodInsn(INVOKESTATIC, HELPER_CLASS, "arg",
|
||||
"(Ljava/lang/String;Ljava/lang/String;"
|
||||
+ typeDescriptor + ")V");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guard against a label which hasn't been resolved. This happens sometimes,
|
||||
* I assume due to a bug in ASM.
|
||||
*/
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String desc, String signature,
|
||||
Label start, Label end, int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
end.getOffset();
|
||||
}
|
||||
catch (IllegalStateException ex)
|
||||
{
|
||||
mv.visitLabel(end);
|
||||
}
|
||||
super.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current line number and generate a call to {@link AgentHelper}
|
||||
* if either writeTraceLine is set to true or the current line was marked by
|
||||
|
|
@ -153,11 +234,32 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
public void visitLineNumber(int xiLineNumber, Label label)
|
||||
{
|
||||
lineNumber = xiLineNumber;
|
||||
if (writeTraceLine || reverseGOTOLines.contains(xiLineNumber))
|
||||
labelLineNos.put(label, xiLineNumber);
|
||||
|
||||
if (writeTraceLine || reverseGOTOLines.contains(xiLineNumber)
|
||||
|| traceLabels.contains(label))
|
||||
{
|
||||
generateCallToAgentHelper(InstrumentationType.BRANCH, lineNumber);
|
||||
writeTraceLine = false;
|
||||
// This check excludes ternary statements where we can't add trace
|
||||
if (numBranchesOnLine < 2)
|
||||
{
|
||||
if (ctorEntryState == CTorEntryState.SEEN_SPECIAL)
|
||||
{
|
||||
addEntryCalls();
|
||||
ctorEntryState = CTorEntryState.ENTRY_WRITTEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
generateCallToAgentHelper(InstrumentationType.BRANCH, lineNumber);
|
||||
}
|
||||
writeTraceLine = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeTraceLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
numBranchesOnLine = 0;
|
||||
super.visitLineNumber(xiLineNumber, label);
|
||||
}
|
||||
|
||||
|
|
@ -168,13 +270,45 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
@Override
|
||||
public void visitInsn(int xiOpCode)
|
||||
{
|
||||
if (xiOpCode == RETURN)
|
||||
if ((ternState == TernaryState.BASE) && (xiOpCode == Opcodes.DUP))
|
||||
{
|
||||
ternState = TernaryState.SEEN_DUP;
|
||||
}
|
||||
else if ((ternState == TernaryState.SEEN_BRANCH)
|
||||
&& (xiOpCode == Opcodes.POP))
|
||||
{
|
||||
ternState = TernaryState.BASE;
|
||||
writeTraceLine = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ternState = TernaryState.BASE;
|
||||
}
|
||||
|
||||
if (xiOpCode == Opcodes.RETURN)
|
||||
{
|
||||
generateCallToAgentHelper(InstrumentationType.EXIT, lineNumber);
|
||||
}
|
||||
super.visitInsn(xiOpCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cTor case where we write entry trace later.
|
||||
*/
|
||||
@Override
|
||||
public void visitMethodInsn(int xiOpCode, String owner, String name,
|
||||
String desc)
|
||||
{
|
||||
if ((ctorEntryState == CTorEntryState.ISCTOR)
|
||||
&& (xiOpCode == Opcodes.INVOKESPECIAL))
|
||||
{
|
||||
ctorEntryState = CTorEntryState.SEEN_SPECIAL;
|
||||
writeTraceLine = true;
|
||||
}
|
||||
|
||||
super.visitMethodInsn(xiOpCode, owner, name, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* A jump instruction indicates that we are about to enter an optional block
|
||||
* of code. We set "writeTraceLine = true;" to ensure that we generate a
|
||||
|
|
@ -183,10 +317,47 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
@Override
|
||||
public void visitJumpInsn(int xiOpCode, Label xiBranchLabel)
|
||||
{
|
||||
writeTraceLine = true;
|
||||
if (ternState == TernaryState.SEEN_DUP)
|
||||
{
|
||||
ternState = TernaryState.SEEN_BRANCH;
|
||||
}
|
||||
|
||||
numBranchesOnLine++;
|
||||
Integer lineNo = labelLineNos.get(xiBranchLabel);
|
||||
if (lineNo == null)
|
||||
{
|
||||
// This is a forward jump
|
||||
writeTraceLine = true;
|
||||
}
|
||||
super.visitJumpInsn(xiOpCode, xiBranchLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try catch handler
|
||||
*/
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler,
|
||||
String type)
|
||||
{
|
||||
traceLabels.add(handler);
|
||||
super.visitTryCatchBlock(start, end, handler, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch block
|
||||
*/
|
||||
@Override
|
||||
public void visitTableSwitchInsn(int min, int max, Label dflt,
|
||||
Label[] labels)
|
||||
{
|
||||
traceLabels.add(dflt);
|
||||
for (Label label : labels)
|
||||
{
|
||||
traceLabels.add(label);
|
||||
}
|
||||
super.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an ENTER/BRANCH/EXIT instrumentation call.
|
||||
*
|
||||
|
|
@ -196,9 +367,9 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
private void generateCallToAgentHelper(InstrumentationType traceType,
|
||||
int lineNumber)
|
||||
{
|
||||
mv.visitLdcInsn(mClassName);
|
||||
mv.visitLdcInsn(className);
|
||||
mv.visitLdcInsn(methodName);
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, lineNumber);
|
||||
mv.visitLdcInsn(lineNumber);
|
||||
switch (traceType)
|
||||
{
|
||||
case ENTER:
|
||||
|
|
@ -232,4 +403,15 @@ public class InstrumentedClassWriter extends ClassWriter
|
|||
{
|
||||
ENTER, BRANCH, EXIT
|
||||
}
|
||||
|
||||
private enum TernaryState
|
||||
{
|
||||
BASE, SEEN_DUP, SEEN_BRANCH
|
||||
/* SEEN_POP */
|
||||
}
|
||||
|
||||
private enum CTorEntryState
|
||||
{
|
||||
NORMALMETHOD, ISCTOR, SEEN_SPECIAL, ENTRY_WRITTEN
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,9 +131,8 @@ public class AgentClientConnection implements Runnable
|
|||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new IOException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package org.intrace.output.trace;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -23,9 +22,12 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
TraceSettings oldSettings = new TraceSettings(traceSettings);
|
||||
traceSettings.parseArgs(args);
|
||||
|
||||
if ((oldSettings.isEntryExitTraceEnabled() != traceSettings.isEntryExitTraceEnabled()) ||
|
||||
(oldSettings.isBranchTraceEnabled() != traceSettings.isBranchTraceEnabled()) ||
|
||||
(oldSettings.isArgTraceEnabled() != traceSettings.isArgTraceEnabled()))
|
||||
if ((oldSettings.isEntryExitTraceEnabled() != traceSettings
|
||||
.isEntryExitTraceEnabled())
|
||||
|| (oldSettings.isBranchTraceEnabled() != traceSettings
|
||||
.isBranchTraceEnabled())
|
||||
|| (oldSettings.isArgTraceEnabled() != traceSettings
|
||||
.isArgTraceEnabled()))
|
||||
{
|
||||
System.out.println("## Trace Settings Changed");
|
||||
}
|
||||
|
|
@ -37,7 +39,7 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
return null;
|
||||
}
|
||||
|
||||
public Map<String,String> getSettingsMap()
|
||||
public Map<String, String> getSettingsMap()
|
||||
{
|
||||
return traceSettings.getSettingsMap();
|
||||
}
|
||||
|
|
@ -47,7 +49,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + byteArg);
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: "
|
||||
+ byteArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +68,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + shortArg);
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: "
|
||||
+ shortArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +87,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + intArg);
|
||||
AgentHelper
|
||||
.writeOutput(className + ":" + methodName + ": Arg: " + intArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +107,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + longArg);
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: "
|
||||
+ longArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +127,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + floatArg);
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: "
|
||||
+ floatArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +147,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + doubleArg);
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: "
|
||||
+ doubleArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +167,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + boolArg);
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: "
|
||||
+ boolArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +187,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + charArg);
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: "
|
||||
+ charArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +207,8 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
{
|
||||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: " + objArg);
|
||||
AgentHelper
|
||||
.writeOutput(className + ":" + methodName + ": Arg: " + objArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +217,7 @@ public class TraceHandler implements IInstrumentationHandler
|
|||
if (argTrace)
|
||||
{
|
||||
AgentHelper.writeOutput(className + ":" + methodName + ": Arg: "
|
||||
+ Arrays.toString(objArrayArg));
|
||||
+ Arrays.deepToString(objArrayArg));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package org.test.intrace.agent;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.intrace.agent.AgentSettings;
|
||||
import org.intrace.shared.AgentConfigConstants;
|
||||
|
||||
public class AgentSettingsTest extends TestCase
|
||||
{
|
||||
public void testAgentSettings()
|
||||
{
|
||||
AgentSettings as = new AgentSettings(
|
||||
AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED
|
||||
+ "true"
|
||||
+ AgentConfigConstants.CLASS_REGEX
|
||||
+ ".*"
|
||||
+ AgentConfigConstants.INSTRU_ENABLED
|
||||
+ "true"
|
||||
+ AgentConfigConstants.SAVE_TRACED_CLASSFILES
|
||||
+ "true"
|
||||
+ AgentConfigConstants.VERBOSE_MODE
|
||||
+ "true");
|
||||
assertEquals(as.allowJarsToBeTraced(), true);
|
||||
assertEquals(as.getClassRegex().pattern(), ".*");
|
||||
assertEquals(as.isInstrumentationEnabled(), true);
|
||||
assertEquals(as.saveTracedClassfiles(), true);
|
||||
assertEquals(as.isVerboseMode(), true);
|
||||
|
||||
as = new AgentSettings(as);
|
||||
assertEquals(as.allowJarsToBeTraced(), true);
|
||||
assertEquals(as.getClassRegex().pattern(), ".*");
|
||||
assertEquals(as.isInstrumentationEnabled(), true);
|
||||
assertEquals(as.saveTracedClassfiles(), true);
|
||||
assertEquals(as.isVerboseMode(), true);
|
||||
|
||||
String toString = as.toString();
|
||||
assertNotNull(toString);
|
||||
|
||||
Map<String, String> settingsMap = as.getSettingsMap();
|
||||
assertEquals(settingsMap.get(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED),
|
||||
"true");
|
||||
assertEquals(settingsMap.get(AgentConfigConstants.CLASS_REGEX), ".*");
|
||||
assertEquals(settingsMap.get(AgentConfigConstants.INSTRU_ENABLED), "true");
|
||||
assertEquals(settingsMap.get(AgentConfigConstants.SAVE_TRACED_CLASSFILES),
|
||||
"true");
|
||||
assertEquals(settingsMap.get(AgentConfigConstants.VERBOSE_MODE), "true");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,663 @@
|
|||
package org.test.intrace.agent;
|
||||
|
||||
import static org.easymock.EasyMock.isA;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.easymock.IAnswer;
|
||||
import org.easymock.classextension.EasyMock;
|
||||
import org.intrace.output.AgentHelper;
|
||||
import org.intrace.output.IInstrumentationHandler;
|
||||
import org.intrace.shared.AgentConfigConstants;
|
||||
import org.intrace.shared.OutputConfigConstants;
|
||||
import org.intrace.shared.TraceConfigConstants;
|
||||
|
||||
/**
|
||||
* This test tests the Agent. To run this test you must run the test with this
|
||||
* JVM argument: "-javaagent:built/traceagent_test.jar="
|
||||
*/
|
||||
public class AgentTest extends TestCase
|
||||
{
|
||||
private Receiver receiver;
|
||||
private Sender sender;
|
||||
private Socket socket;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
deleteOldClassFiles();
|
||||
AgentHelper.instrumentationHandlers.clear();
|
||||
connectToAgent();
|
||||
testSetting(AgentConfigConstants.INSTRU_ENABLED, "false");
|
||||
}
|
||||
|
||||
private void deleteOldClassFiles()
|
||||
{
|
||||
File genbin = new File("./genbin/");
|
||||
File[] files = genbin.listFiles();
|
||||
if (files != null)
|
||||
{
|
||||
for (int i = 0; i < files.length; i++)
|
||||
{
|
||||
if (files[i].isDirectory())
|
||||
{
|
||||
deleteDirectory(files[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean deleteDirectory(File path)
|
||||
{
|
||||
if (path.exists())
|
||||
{
|
||||
File[] files = path.listFiles();
|
||||
for (int i = 0; i < files.length; i++)
|
||||
{
|
||||
if (files[i].isDirectory())
|
||||
{
|
||||
deleteDirectory(files[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
return (path.delete());
|
||||
}
|
||||
|
||||
public void testGetSettings() throws Exception
|
||||
{
|
||||
sender.sendMessage("getsettings");
|
||||
Object settingsResponse = receiver.incomingMessages.take();
|
||||
assertNotNull(settingsResponse);
|
||||
assertTrue(settingsResponse instanceof Map<?, ?>);
|
||||
}
|
||||
|
||||
public void testHelp() throws Exception
|
||||
{
|
||||
sender.sendMessage("help");
|
||||
Object helpResponse = receiver.incomingMessages.take();
|
||||
assertNotNull(helpResponse);
|
||||
assertTrue(helpResponse instanceof Set<?>);
|
||||
Set<String> expectedHelpResponse = new HashSet<String>();
|
||||
expectedHelpResponse.addAll(AgentConfigConstants.COMMANDS);
|
||||
expectedHelpResponse.addAll(OutputConfigConstants.COMMANDS);
|
||||
expectedHelpResponse.addAll(TraceConfigConstants.COMMANDS);
|
||||
assertEquals(helpResponse, expectedHelpResponse);
|
||||
}
|
||||
|
||||
public void testSettings() throws Exception
|
||||
{
|
||||
// Boolean settings
|
||||
testSetting(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED, "true");
|
||||
testSetting(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED, "false");
|
||||
testSetting(AgentConfigConstants.INSTRU_ENABLED, "true");
|
||||
testSetting(AgentConfigConstants.INSTRU_ENABLED, "false");
|
||||
testSetting(AgentConfigConstants.SAVE_TRACED_CLASSFILES, "true");
|
||||
testSetting(AgentConfigConstants.SAVE_TRACED_CLASSFILES, "false");
|
||||
testSetting(AgentConfigConstants.VERBOSE_MODE, "true");
|
||||
testSetting(AgentConfigConstants.VERBOSE_MODE, "false");
|
||||
|
||||
// Regex (Test in verbose mode to exercise the verbose code
|
||||
testSetting(AgentConfigConstants.CLASS_REGEX, "foo.*");
|
||||
testSetting(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED, "true");
|
||||
testSetting(AgentConfigConstants.INSTRU_ENABLED, "true");
|
||||
testSetting(AgentConfigConstants.VERBOSE_MODE, "true");
|
||||
testSetting(AgentConfigConstants.CLASS_REGEX, ".*");
|
||||
}
|
||||
|
||||
public void testBranchPatterns() throws Throwable
|
||||
{
|
||||
// Create and init the mock
|
||||
IInstrumentationHandler testHandler = EasyMock
|
||||
.createMock(IInstrumentationHandler.class);
|
||||
EasyMock.expect(testHandler.getResponse(isA(String.class))).andReturn(null)
|
||||
.anyTimes();
|
||||
EasyMock.expect(testHandler.getSettingsMap())
|
||||
.andReturn(new HashMap<String, String>()).anyTimes();
|
||||
|
||||
// Capture objects
|
||||
final BlockingQueue<String> capturedTrace = new LinkedBlockingQueue<String>();
|
||||
IAnswer<Object> entryTraceWriter = new IAnswer<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object answer() throws Throwable
|
||||
{
|
||||
Object[] args = EasyMock.getCurrentArguments();
|
||||
capturedTrace.put("Enter:##:" + Arrays.toString(args));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
IAnswer<Object> branchTraceWriter = new IAnswer<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object answer() throws Throwable
|
||||
{
|
||||
Object[] args = EasyMock.getCurrentArguments();
|
||||
capturedTrace.put("Branch:##:" + Arrays.toString(args));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
IAnswer<Object> exitTraceWriter = new IAnswer<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object answer() throws Throwable
|
||||
{
|
||||
Object[] args = EasyMock.getCurrentArguments();
|
||||
capturedTrace.put("Exit:##:" + Arrays.toString(args));
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Expect trace calls
|
||||
testHandler.enter(isA(String.class), isA(String.class), EasyMock.anyInt());
|
||||
EasyMock.expectLastCall().andAnswer(entryTraceWriter).anyTimes();
|
||||
testHandler.branch(isA(String.class), isA(String.class), EasyMock.anyInt());
|
||||
EasyMock.expectLastCall().andAnswer(branchTraceWriter).anyTimes();
|
||||
testHandler.exit(isA(String.class), isA(String.class), EasyMock.anyInt());
|
||||
EasyMock.expectLastCall().andAnswer(exitTraceWriter).anyTimes();
|
||||
|
||||
testHandler
|
||||
.arg(isA(String.class), isA(String.class), EasyMock.anyBoolean());
|
||||
EasyMock.expectLastCall().anyTimes();
|
||||
testHandler.arg(isA(String.class), isA(String.class), EasyMock.anyObject());
|
||||
EasyMock.expectLastCall().anyTimes();
|
||||
testHandler.arg(isA(String.class), isA(String.class), EasyMock.anyInt());
|
||||
EasyMock.expectLastCall().anyTimes();
|
||||
|
||||
EasyMock.replay(testHandler);
|
||||
AgentHelper.instrumentationHandlers.put(testHandler, new Object());
|
||||
|
||||
// Setup agent
|
||||
testSetting(AgentConfigConstants.INSTRU_ENABLED, "false");
|
||||
testSetting(AgentConfigConstants.CLASS_REGEX, ".*BranchPatterns.*");
|
||||
testSetting(AgentConfigConstants.VERBOSE_MODE, "false");
|
||||
testSetting(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED, "false");
|
||||
testSetting(AgentConfigConstants.SAVE_TRACED_CLASSFILES, "true");
|
||||
testSetting(AgentConfigConstants.INSTRU_ENABLED, "true");
|
||||
|
||||
// Run Patterns thread
|
||||
BranchPatterns branchPatterns = new BranchPatterns();
|
||||
Thread patternThread = new Thread(branchPatterns);
|
||||
patternThread.start();
|
||||
patternThread.join();
|
||||
if (branchPatterns.th != null)
|
||||
{
|
||||
throw branchPatterns.th;
|
||||
}
|
||||
|
||||
// Verify that we got all of the expected calls
|
||||
EasyMock.verify(testHandler);
|
||||
|
||||
// Parse the trace
|
||||
Map<String, TraceData> parsedTraceData = new HashMap<String, TraceData>();
|
||||
String traceLine = capturedTrace.poll();
|
||||
while (traceLine != null)
|
||||
{
|
||||
parseLine(parsedTraceData, traceLine);
|
||||
traceLine = capturedTrace.poll();
|
||||
}
|
||||
|
||||
// Verify the trace
|
||||
assertNotNull(parsedTraceData.get("switchblock"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("switchblock");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(4, trData.branchLines.size());
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("ternary"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("ternary");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(0, trData.branchLines.size());
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("trycatchfinally"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("trycatchfinally");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(1, trData.branchLines.size());
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("whileloop"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("whileloop");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(2, trData.branchLines.size());
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("forloop"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("forloop");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(2, trData.branchLines.size());
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("singlelineif"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("singlelineif");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(1, trData.branchLines.size());
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("ifthenelse"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("ifthenelse");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(2, trData.branchLines.size());
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("ifthenelseifelse"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("ifthenelseifelse");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(5, trData.branchLines.size());
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("dowhile"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("dowhile");
|
||||
assertTrue(trData.seenEnter);
|
||||
assertTrue(trData.seenExit);
|
||||
assertEquals(2, trData.branchLines.size());
|
||||
}
|
||||
}
|
||||
|
||||
public void testArgumentTypes() throws Throwable
|
||||
{
|
||||
// Create and init the mock
|
||||
final BlockingQueue<String> capturedTrace = new LinkedBlockingQueue<String>();
|
||||
IInstrumentationHandler testHandler = new ArgCapture(capturedTrace);
|
||||
AgentHelper.instrumentationHandlers.put(testHandler, new Object());
|
||||
|
||||
// Setup agent
|
||||
testSetting(AgentConfigConstants.INSTRU_ENABLED, "false");
|
||||
testSetting(AgentConfigConstants.CLASS_REGEX, ".*ArgumentTypes.*");
|
||||
testSetting(AgentConfigConstants.VERBOSE_MODE, "false");
|
||||
testSetting(AgentConfigConstants.ALLOW_JARS_TO_BE_TRACED, "false");
|
||||
testSetting(AgentConfigConstants.SAVE_TRACED_CLASSFILES, "true");
|
||||
testSetting(AgentConfigConstants.INSTRU_ENABLED, "true");
|
||||
|
||||
// Run Patterns thread
|
||||
ArgumentTypes argTypes = new ArgumentTypes();
|
||||
Thread patternThread = new Thread(argTypes);
|
||||
patternThread.start();
|
||||
patternThread.join();
|
||||
if (argTypes.th != null)
|
||||
{
|
||||
throw argTypes.th;
|
||||
}
|
||||
|
||||
// Parse the trace
|
||||
Map<String, TraceData> parsedTraceData = new HashMap<String, TraceData>();
|
||||
String traceLine = capturedTrace.poll();
|
||||
while (traceLine != null)
|
||||
{
|
||||
parseLine(parsedTraceData, traceLine);
|
||||
traceLine = capturedTrace.poll();
|
||||
}
|
||||
|
||||
// Verify the trace
|
||||
assertNotNull(parsedTraceData.get("byteArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("byteArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("0", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("byteArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("byteArrayArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("[1]", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("shortArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("shortArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("2", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("shortArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("shortArrayArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("[3]", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("intArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("intArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("4", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("intArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("intArrayArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("[5]", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("longArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("longArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("6", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("longArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("longArrayArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("[7]", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("floatArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("floatArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("8.0", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("floatArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("floatArrayArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("[9.0]", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("doubleArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("doubleArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("10.0", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("doubleArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("doubleArrayArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("[11.0]", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("boolArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("boolArg");
|
||||
assertEquals(2, trData.args.size());
|
||||
assertEquals("true", trData.args.get(0));
|
||||
assertEquals("false", trData.args.get(1));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("boolArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("boolArrayArg");
|
||||
assertEquals(2, trData.args.size());
|
||||
assertEquals("[true]", trData.args.get(0));
|
||||
assertEquals("[false]", trData.args.get(1));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("boolArrayArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("boolArrayArrayArg");
|
||||
assertEquals(2, trData.args.size());
|
||||
assertEquals("[[true]]", trData.args.get(0));
|
||||
assertEquals("[[false]]", trData.args.get(1));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("charArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("charArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("2", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("charArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("charArrayArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("[3]", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("objArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("objArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("obj", trData.args.get(0));
|
||||
}
|
||||
|
||||
assertNotNull(parsedTraceData.get("objArrayArg"));
|
||||
{
|
||||
TraceData trData = parsedTraceData.get("objArrayArg");
|
||||
assertEquals(1, trData.args.size());
|
||||
assertEquals("[obj]", trData.args.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
private void parseLine(Map<String, TraceData> parsedTraceData,
|
||||
String traceLine)
|
||||
{
|
||||
String[] traceParts = traceLine.split(":##:");
|
||||
String traceType = traceParts[0];
|
||||
String traceLineData = traceParts[1];
|
||||
traceLineData = traceLineData.substring(1, traceLineData.length() - 1);
|
||||
String[] dataParts = traceLineData.split(",");
|
||||
String methodSig = dataParts[1].trim();
|
||||
|
||||
TraceData traceData = parsedTraceData.get(methodSig);
|
||||
if (traceData == null)
|
||||
{
|
||||
traceData = new TraceData();
|
||||
parsedTraceData.put(methodSig, traceData);
|
||||
}
|
||||
|
||||
if (traceType.equals("Enter"))
|
||||
{
|
||||
traceData.seenEnter = true;
|
||||
}
|
||||
else if (traceType.equals("Exit"))
|
||||
{
|
||||
traceData.seenExit = true;
|
||||
}
|
||||
else if (traceType.equals("Branch"))
|
||||
{
|
||||
traceData.branchLines.add(Integer.parseInt(dataParts[2].trim()));
|
||||
}
|
||||
else if (traceType.equals("Arg"))
|
||||
{
|
||||
traceData.args.add(dataParts[2].trim());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void testSetting(String configConstant, String configValue)
|
||||
throws Exception
|
||||
{
|
||||
// Set setting
|
||||
sender.sendMessage(configConstant + configValue);
|
||||
Object okResponse = receiver.incomingMessages.take();
|
||||
assertNotNull(okResponse);
|
||||
assertTrue(okResponse instanceof String);
|
||||
assertEquals(okResponse, "OK");
|
||||
|
||||
// Get settings
|
||||
sender.sendMessage("getsettings");
|
||||
Object settingsResponse = receiver.incomingMessages.take();
|
||||
assertNotNull(settingsResponse);
|
||||
assertTrue(settingsResponse instanceof Map<?, ?>);
|
||||
Map<String, String> settingsResponseMap = (Map<String, String>) settingsResponse;
|
||||
assertEquals(configValue, settingsResponseMap.get(configConstant));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
receiver.stop();
|
||||
sender.stop();
|
||||
socket.close();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
private void connectToAgent() throws Exception
|
||||
{
|
||||
String host = "localhost";
|
||||
int port = 9123;
|
||||
|
||||
socket = new Socket();
|
||||
socket.connect(new InetSocketAddress(host, port));
|
||||
|
||||
// Start threads
|
||||
receiver = new Receiver(socket.getInputStream());
|
||||
receiver.start();
|
||||
sender = new Sender(socket.getOutputStream());
|
||||
sender.start();
|
||||
}
|
||||
|
||||
private static class Sender implements Runnable
|
||||
{
|
||||
private final OutputStream outputStream;
|
||||
private final BlockingQueue<String> outgoingMessages = new LinkedBlockingQueue<String>();
|
||||
private Thread th;
|
||||
|
||||
public Sender(OutputStream outputStream)
|
||||
{
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
||||
public void stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
outputStream.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// Throw away
|
||||
}
|
||||
th.interrupt();
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
th = new Thread(this);
|
||||
th.setDaemon(true);
|
||||
th.setName("Sender");
|
||||
th.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
String message = outgoingMessages.take();
|
||||
ObjectOutputStream objOut = new ObjectOutputStream(outputStream);
|
||||
objOut.writeObject(message);
|
||||
objOut.flush();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Do something
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(String message)
|
||||
{
|
||||
try
|
||||
{
|
||||
outgoingMessages.put(message);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Receiver implements Runnable
|
||||
{
|
||||
private final InputStream inputStream;
|
||||
private final BlockingQueue<Object> incomingMessages = new LinkedBlockingQueue<Object>();
|
||||
private Thread th;
|
||||
|
||||
public Receiver(InputStream inputStream)
|
||||
{
|
||||
this.inputStream = inputStream;
|
||||
}
|
||||
|
||||
public void stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// Throw away
|
||||
}
|
||||
th.interrupt();
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
th = new Thread(this);
|
||||
th.setDaemon(true);
|
||||
th.setName("Receiver");
|
||||
th.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ObjectInputStream objIn = new ObjectInputStream(inputStream);
|
||||
Object receivedMessage = objIn.readObject();
|
||||
incomingMessages.put(receivedMessage);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Do something
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
package org.test.intrace.agent;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
import org.intrace.output.IInstrumentationHandler;
|
||||
|
||||
public class ArgCapture implements IInstrumentationHandler
|
||||
{
|
||||
private final BlockingQueue<String> capturedTrace;
|
||||
|
||||
public ArgCapture(BlockingQueue<String> capturedTrace)
|
||||
{
|
||||
this.capturedTrace = capturedTrace;
|
||||
}
|
||||
|
||||
private void addArg(String arg)
|
||||
{
|
||||
capturedTrace.add(arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, byte byteArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + byteArg + "]");
|
||||
}
|
||||
|
||||
public void arg(String className, String methodName, byte[] byteArrayArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.toString(byteArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, short shortArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + shortArg + "]");
|
||||
}
|
||||
|
||||
public void arg(String className, String methodName, short[] shortArrayArg)
|
||||
{
|
||||
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.toString(shortArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, int intArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + intArg + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, int[] intArrayArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.toString(intArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, long longArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + longArg + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, long[] longArrayArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.toString(longArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, float floatArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + floatArg + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, float[] floatArrayArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.toString(floatArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, double doubleArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + doubleArg + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, double[] doubleArrayArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.toString(doubleArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, boolean boolArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + boolArg + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, boolean[] boolArrayArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.toString(boolArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, char charArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + charArg + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, char[] charArrayArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.toString(charArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arg(String className, String methodName, Object objArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", " + objArg + "]");
|
||||
}
|
||||
|
||||
public void arg(String className, String methodName, Object[] objArrayArg)
|
||||
{
|
||||
addArg("Arg:##:[" + className + ", " + methodName + ", "
|
||||
+ Arrays.deepToString(objArrayArg) + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void branch(String className, String methodName, int lineNo)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter(String className, String methodName, int lineNo)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(String className, String methodName, int lineNo)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResponse(String args)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getSettingsMap()
|
||||
{
|
||||
return new HashMap<String, String>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
package org.test.intrace.agent;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ArgumentTypes implements Runnable
|
||||
{
|
||||
public Throwable th = null;
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
byteArg((byte) 0);
|
||||
byteArrayArg(new byte[]
|
||||
{ 1 });
|
||||
|
||||
shortArg((short) 2);
|
||||
shortArrayArg(new short[]
|
||||
{ 3 });
|
||||
|
||||
intArg(4);
|
||||
intArrayArg(new int[]
|
||||
{ 5 });
|
||||
|
||||
longArg(6l);
|
||||
longArrayArg(new long[]
|
||||
{ 7l });
|
||||
|
||||
floatArg(8f);
|
||||
floatArrayArg(new float[]
|
||||
{ 9f });
|
||||
|
||||
doubleArg(10d);
|
||||
doubleArrayArg(new double[]
|
||||
{ 11d });
|
||||
|
||||
boolArg(true);
|
||||
boolArg(false);
|
||||
boolArrayArg(new boolean[]
|
||||
{ true });
|
||||
boolArrayArg(new boolean[]
|
||||
{ false });
|
||||
boolArrayArrayArg(new boolean[][]
|
||||
{ new boolean[]
|
||||
{ true } });
|
||||
boolArrayArrayArg(new boolean[][]
|
||||
{ new boolean[]
|
||||
{ false } });
|
||||
|
||||
charArg('2');
|
||||
charArrayArg(new char[]
|
||||
{ '3' });
|
||||
|
||||
Object objToStr = new Object()
|
||||
{
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "obj";
|
||||
}
|
||||
};
|
||||
objArg(objToStr);
|
||||
objArrayArg(new Object[]
|
||||
{ objToStr });
|
||||
}
|
||||
catch (Throwable thr)
|
||||
{
|
||||
th = thr;
|
||||
}
|
||||
}
|
||||
|
||||
private void byteArg(byte arg)
|
||||
{
|
||||
setProperty(Byte.toString(arg));
|
||||
}
|
||||
|
||||
private void byteArrayArg(byte[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void shortArg(short arg)
|
||||
{
|
||||
setProperty(Short.toString(arg));
|
||||
}
|
||||
|
||||
private void shortArrayArg(short[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void intArg(int arg)
|
||||
{
|
||||
setProperty(Integer.toString(arg));
|
||||
}
|
||||
|
||||
private void intArrayArg(int[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void longArg(long arg)
|
||||
{
|
||||
setProperty(Long.toString(arg));
|
||||
}
|
||||
|
||||
private void longArrayArg(long[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void floatArg(float arg)
|
||||
{
|
||||
setProperty(Float.toString(arg));
|
||||
}
|
||||
|
||||
private void floatArrayArg(float[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void doubleArg(double arg)
|
||||
{
|
||||
setProperty(Double.toString(arg));
|
||||
}
|
||||
|
||||
private void doubleArrayArg(double[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void boolArg(boolean arg)
|
||||
{
|
||||
setProperty(Boolean.toString(arg));
|
||||
}
|
||||
|
||||
private void boolArrayArg(boolean[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void boolArrayArrayArg(boolean[][] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void charArg(char arg)
|
||||
{
|
||||
setProperty(Character.toString(arg));
|
||||
}
|
||||
|
||||
private void charArrayArg(char[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void objArg(Object arg)
|
||||
{
|
||||
setProperty(arg.toString());
|
||||
}
|
||||
|
||||
private void objArrayArg(Object[] arg)
|
||||
{
|
||||
setProperty(Arrays.toString(arg));
|
||||
}
|
||||
|
||||
private void setProperty(String value)
|
||||
{
|
||||
System.setProperty("test-key", value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
package org.test.intrace.agent;
|
||||
|
||||
public class BranchPatterns implements Runnable
|
||||
{
|
||||
public Throwable th = null;
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
dowhile();
|
||||
forloop();
|
||||
whileloop();
|
||||
switchblock(1);
|
||||
switchblock(2);
|
||||
ternary(true);
|
||||
ternary(false);
|
||||
trycatchfinally();
|
||||
singlelineif(true);
|
||||
ifthenelse(true);
|
||||
ifthenelse(false);
|
||||
ifthenelseifelse(true, false);
|
||||
ifthenelseifelse(false, true);
|
||||
ifthenelseifelse(false, false);
|
||||
}
|
||||
catch (Throwable thr)
|
||||
{
|
||||
th = thr;
|
||||
}
|
||||
}
|
||||
|
||||
private void dowhile()
|
||||
{
|
||||
int loopCount = 0;
|
||||
do
|
||||
{
|
||||
setProperty();
|
||||
loopCount++;
|
||||
}
|
||||
while (loopCount < 2);
|
||||
}
|
||||
|
||||
private void whileloop()
|
||||
{
|
||||
int loopCount = 0;
|
||||
while (loopCount < 2)
|
||||
{
|
||||
setProperty();
|
||||
loopCount++;
|
||||
}
|
||||
}
|
||||
|
||||
private void forloop()
|
||||
{
|
||||
for (int ii = 0; ii < 2; ii++)
|
||||
{
|
||||
setProperty();
|
||||
}
|
||||
}
|
||||
|
||||
private void switchblock(int arg)
|
||||
{
|
||||
switch (arg)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
setProperty("1");
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
setProperty("2");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ternary(boolean arg)
|
||||
{
|
||||
String value = (arg ? "a" : "b");
|
||||
setProperty(value);
|
||||
}
|
||||
|
||||
private void trycatchfinally()
|
||||
{
|
||||
try
|
||||
{
|
||||
setProperty();
|
||||
throw new Exception("test");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
setProperty();
|
||||
}
|
||||
finally
|
||||
{
|
||||
setProperty();
|
||||
}
|
||||
}
|
||||
|
||||
private void singlelineif(boolean arg)
|
||||
{
|
||||
if (arg)
|
||||
setProperty();
|
||||
}
|
||||
|
||||
private void ifthenelse(boolean arg)
|
||||
{
|
||||
if (arg)
|
||||
{
|
||||
setProperty();
|
||||
}
|
||||
else
|
||||
{
|
||||
setProperty();
|
||||
}
|
||||
}
|
||||
|
||||
private void ifthenelseifelse(boolean arg1, boolean arg2)
|
||||
{
|
||||
if (arg1)
|
||||
{
|
||||
setProperty();
|
||||
}
|
||||
else if (arg2)
|
||||
{
|
||||
setProperty();
|
||||
}
|
||||
else
|
||||
{
|
||||
setProperty();
|
||||
}
|
||||
}
|
||||
|
||||
private void setProperty()
|
||||
{
|
||||
setProperty(Long.toString(System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
private void setProperty(String value)
|
||||
{
|
||||
System.setProperty("test-key", value);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package org.test.intrace.agent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TraceData
|
||||
{
|
||||
public boolean seenEnter;
|
||||
public boolean seenExit;
|
||||
public final List<Integer> branchLines = new ArrayList<Integer>();
|
||||
public final List<String> args = new ArrayList<String>();
|
||||
}
|
||||
Loading…
Reference in New Issue