To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

Commit a77dc9b8 authored by john's avatar john
Browse files

redid the Tagging of objects to work around a strange stack usage case in eclipse

parent 6e070440
......@@ -22,18 +22,6 @@
</condition>
<property name="download-dir" value="${agent-dir}/download"/>
<!--
<property name="asm-verison" value="3.2"/>
<property name="asm-jar" value="asm-${asm-verison}.jar"/>
<property name="asm-analysis-jar" value="asm-analysis-${asm-verison}.jar"/>
<property name="asm-commons-jar" value="asm-commons-${asm-verison}.jar"/>
<property name="asm-parent-jar" value="asm-parent-${asm-verison}.jar"/>
<property name="asm-tree-jar" value="asm-tree-${asm-verison}.jar"/>
<property name="asm-util-jar" value="asm-util-${asm-verison}.jar"/>
<property name="asm-xml-jar" value="asm-xml-${asm-verison}.jar"/>
<property name="asm-zip" value="asm-${asm-verison}-bin.zip"/>
<property name="asm-url" value="http://download.forge.objectweb.org/asm"/>
-->
<!-- http://zlib.net/zlib-1.2.5.tar.gz -->
......@@ -70,20 +58,6 @@
<arg value="configure"/>
</exec>
<exec executable="make" dir="${agent-dir}/build/${zlib-basename}" />
<!--
<antcall target="check-source">
<param name="target-file" value="${asm-zip}" />
<param name="target-dir" value="${download-dir}" />
<param name="target-url" value="${asm-url}"/>
</antcall>
<unzip src="${download-dir}/${asm-zip}" dest="${agent-dir}/build">
<fileset dir=".">
<include name="asm-3.2/lib/*.jar"/>
</fileset>
</unzip>
<copy file="${agent-dir}/build/asm-3.2/lib/${asm-jar}" todir="${dist-dir}"/>
<copy file="${agent-dir}/build/asm-3.2/lib/${asm-commons-jar}" todir="${dist-dir}"/>
-->
<copy file="${asm-jar}" todir="${dist-dir}"/>
<copy file="${asm-commons-jar}" todir="${dist-dir}"/>
......
......@@ -550,7 +550,7 @@ callbackClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* env,
*new_class_data = NULL;
*new_class_data_len = 0;
sprintf(command, "java -classpath dist/agent.jar:dist/asm-3.2.jar:dist/asm-commons-3.2.jar org.dacapo.instrument.Instrument '%s' '%s' '%s' \"%s\"",infile,outfile,(name!=NULL?name:"NULL"),agentOptions);
sprintf(command, "java -classpath dist/agent.jar:dist/asm-3.3.jar:dist/asm-commons-3.3.jar org.dacapo.instrument.Instrument '%s' '%s' '%s' \"%s\"",infile,outfile,(name!=NULL?name:"NULL"),agentOptions);
if (system(command) == 0) {
readClassData(infile,new_class_data,new_class_data_len);
}
......
......@@ -35,6 +35,7 @@ static jint forceGC(JNIEnv *env) {
gcCount = 0;
rawMonitorEnter(&lockLog);
log_field_string(LOG_PREFIX_GC);
log_field_current_time();
log_eol();
rawMonitorExit(&lockLog);
jint res = JVMTI_FUNC_PTR(baseEnv,ForceGarbageCollection)(baseEnv);
......
......@@ -177,6 +177,9 @@ public final class Agent {
if (nodes[i][j] != null) {
// System.err.println("Alloc:"+nodes[i][j].getClass());
internalAllocReport(t,nodes[i][j],nodes[i][j].getClass());
if (firstReportSinceForceGC) {
reportHeapAfterForceGC();
}
nodes[i][j] = null;
}
}
......@@ -295,12 +298,16 @@ public final class Agent {
public static void start() {
if (agentThread.setLogon(true)) {
System.err.println("START:");
(new Exception()).printStackTrace();
internalStart();
}
}
public static void stop() {
if (agentThread.setLogon(false)) {
System.err.println("STOP:");
(new Exception()).printStackTrace();
internalStop();
}
}
......@@ -352,11 +359,12 @@ public final class Agent {
public static void reportHeapAfterForceGC() {
if (firstReportSinceForceGC) {
firstReportSinceForceGC = false;
reportHeapAfterForceGCSync();
}
}
public static void reportHeap() {
public synchronized static void reportHeap() {
long free = runtime.freeMemory();
long max = runtime.maxMemory();
long total = runtime.totalMemory();
......@@ -402,6 +410,7 @@ public final class Agent {
private static synchronized void reportHeapAfterForceGCSync() {
if (firstReportSinceForceGC) {
firstReportSinceForceGC = false;
reportHeap();
}
}
......
......@@ -15,9 +15,10 @@ import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AdviceAdapter;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.LocalVariablesSorter;
import org.objectweb.asm.commons.Method;
public class AllocateInstrument extends ClassAdapter {
public class AllocateInstrument extends Instrument {
// we need to instrument a call to alloc in the constructor, after the super
// class init but before the other code. This should call the reportAlloc
......@@ -75,8 +76,31 @@ public class AllocateInstrument extends ClassAdapter {
private LinkedList<String> excludePackages = new LinkedList<String>();
public AllocateInstrument(ClassVisitor cv, String excludeList, boolean logPointerChange) {
super(cv);
private static final Type OBJECT_TYPE = Type.getType(Object.class);
private static class Pair {
public String type;
public int var;
}
private static class CountLocals extends MethodAdapter {
int max;
public CountLocals(int access, MethodVisitor mv) {
super(mv);
max = ((access & Opcodes.ACC_STATIC)!=0)?-1:0;
}
public int getMaxLocals() {
super.visitCode();
return max;
}
public void visitVarInsn(int opcode, int var) {
super.visitVarInsn(opcode, var);
max = Math.max(max, var);
}
};
public AllocateInstrument(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal, String excludeList, boolean logPointerChange) {
super(cv, methodToLargestLocal);
this.logPointerChange = logPointerChange;
// always add the instrument package to the exclude list
......@@ -96,7 +120,6 @@ public class AllocateInstrument extends ClassAdapter {
this.name = name;
this.access = access;
this.superName = superName;
// this.type = Type.getType(name);
super.visit(version, access, name, signature, superName, interfaces);
}
......@@ -108,9 +131,13 @@ public class AllocateInstrument extends ClassAdapter {
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (!done && instrument() && instrument(access))
return new AllocateInstrumentMethod(access, name, desc, signature, exceptions, super.visitMethod(access,name,desc,signature,exceptions), logPointerChange);
else
if (!done && instrument() && instrument(access)) {
// CountLocals locals = new CountLocals(access, super.visitMethod(access,name,desc,signature,exceptions));
// int nextLocal = 0; // locals.getMaxLocals()+1;
// LocalVariablesSorter lvs = new LocalVariablesSorter(access, desc, super.visitMethod(access, name, desc, signature, exceptions));
return new AllocateInstrumentMethod(access, name, desc, signature, exceptions, super.visitMethod(access, name, desc, signature, exceptions), logPointerChange);
} else
return super.visitMethod(access,name,desc,signature,exceptions);
}
......@@ -224,6 +251,10 @@ public class AllocateInstrument extends ClassAdapter {
boolean constructor;
boolean firstInstruction;
private String encodedName;
private int localsBase = 0;
private int maxLocals;
private MethodVisitor mv;
private Label methodStartLabel;
private String[] exceptions;
private boolean methodDone;
......@@ -234,16 +265,23 @@ public class AllocateInstrument extends ClassAdapter {
private static final boolean DO_INC_DEC = true;
private static final boolean DO_NEW_INVOKESPECIAL_SEQUENCE = true;
LinkedList<String> newTypeStack = new LinkedList<String>();
AllocateInstrumentMethod(int access, String name, String desc, String signature, String[] exceptions, MethodVisitor mv, boolean logPointerChanges) {
super(mv, access, name, desc);
this.constructor = DO_INC_DEC && CONSTRUCTOR.equals(name);
// LinkedList<String> newTypeStack = new LinkedList<String>();
LinkedList<Pair> newTypeStack = new LinkedList<Pair>();
AllocateInstrumentMethod(int access, String methodName, String desc, String signature, String[] exceptions, MethodVisitor mv, boolean logPointerChanges) {
super(mv, access, methodName, desc);
this.mv = mv;
this.constructor = DO_INC_DEC && CONSTRUCTOR.equals(methodName);
this.firstInstruction = constructor;
this.methodStartLabel = null;
this.exceptions = exceptions;
this.methodDone = false;
this.doneSuperConstructor = !constructor;
this.encodedName = Instrument.encodeMethodName(name, methodName, desc);
if (! methodToLargestLocal.containsKey(this.encodedName))
methodToLargestLocal.put(this.encodedName, Instrument.getArgumentSizes(access,desc));
this.localsBase = methodToLargestLocal.get(this.encodedName);
this.maxLocals = this.localsBase;
}
public void onMethodExit(int opcode) {
......@@ -310,11 +348,12 @@ public class AllocateInstrument extends ClassAdapter {
super.visitMethodInsn(opcode,owner,methodName,desc);
if (opcode == Opcodes.INVOKESPECIAL && CONSTRUCTOR.equals(methodName)) {
if (DO_NEW_INVOKESPECIAL_SEQUENCE && !newTypeStack.isEmpty()) {
String type = newTypeStack.removeLast();
if (! type.equals(owner)) {
System.err.println("Excepted type: "+type+" found: "+owner);
Pair p = newTypeStack.removeLast();
if (! p.type.equals(owner)) {
System.err.println("Excepted type: "+p.type+" found: "+owner);
System.exit(10);
}
super.visitVarInsn(Opcodes.ALOAD,p.var);
addLog(false);
}
if (superName.equals(owner)) {
......@@ -375,8 +414,17 @@ public class AllocateInstrument extends ClassAdapter {
if (opcode == Opcodes.ANEWARRAY)
addLog(true);
else if (DO_NEW_INVOKESPECIAL_SEQUENCE && opcode == Opcodes.NEW) {
newTypeStack.addLast(type);
super.visitInsn(Opcodes.DUP);
Pair p = new Pair();
p.type = type;
p.var = this.localsBase + 1 + newTypeStack.size();
if (this.maxLocals < p.var) {
this.maxLocals = p.var;
methodToLargestLocal.put(this.encodedName, new Integer(p.var));
}
super.setLocalType(p.var,OBJECT_TYPE); // super.newLocal(OBJECT_TYPE);
newTypeStack.addLast(p);
super.visitVarInsn(Opcodes.ASTORE,p.var);
}
}
public void visitIntInsn(int opcode, int operand) {
......
......@@ -15,7 +15,7 @@ import org.objectweb.asm.commons.Method;
import java.util.TreeMap;
import java.util.Set;
public class CallChainInstrument extends ClassAdapter {
public class CallChainInstrument extends Instrument {
private static final String INSTRUMENT_PACKAGE = "org/dacapo/instrument/";
......@@ -31,8 +31,8 @@ public class CallChainInstrument extends ClassAdapter {
private boolean done = false;
private boolean found = false;
public CallChainInstrument(ClassVisitor cv) {
super(cv);
public CallChainInstrument(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal) {
super(cv, methodToLargestLocal);
this.cv = cv;
}
......
package org.dacapo.instrument;
import java.util.LinkedList;
import java.util.TreeMap;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
......@@ -14,7 +15,7 @@ import org.objectweb.asm.commons.AdviceAdapter;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
public class ClinitInstrument extends ClassAdapter {
public class ClinitInstrument extends Instrument {
private static final int CLINIT_ACCESS = Opcodes.ACC_STATIC;
private static final String CLINIT_NAME = "<clinit>";
......@@ -37,8 +38,8 @@ public class ClinitInstrument extends ClassAdapter {
private LinkedList<String> excludePackages = new LinkedList<String>();
public ClinitInstrument(ClassVisitor cv, String excludeList) {
super(cv);
public ClinitInstrument(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal, String excludeList) {
super(cv, methodToLargestLocal);
this.cv = cv;
excludePackages.add(INSTRUMENT_PACKAGE);
......
package org.dacapo.instrument;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.TreeMap;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class Instrument {
import org.objectweb.asm.commons.AdviceAdapter;
public class Instrument extends ClassAdapter {
protected TreeMap<String,Integer> methodToLargestLocal;
public Instrument(ClassVisitor arg0, TreeMap<String,Integer> methodToLargestLocal) {
super(arg0);
this.methodToLargestLocal = methodToLargestLocal;
}
private static Options options = null;
......@@ -29,43 +46,55 @@ public class Instrument {
}
try {
TreeMap<String,Integer> methodToLargestLocal = new TreeMap<String,Integer>();
ClassReader reader = readClassFromFile(infile);
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = writer;
cv = new LocalSizes(writer, methodToLargestLocal);
reader.accept(cv,ClassReader.EXPAND_FRAMES);
reader = readClassFromFile(infile);
cv = writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
options = new Options(commandLineOptions);
ClassVisitor cv = writer;
cv = new SystemInstrument(cv, methodToLargestLocal);
if (options.has(Options.RUNTIME))
cv = new RuntimeInstrument(cv);
cv = new RuntimeInstrument(cv, methodToLargestLocal);
if (options.has(Options.MONITOR))
cv = new MonitorInstrument(cv);
cv = new MonitorInstrument(cv, methodToLargestLocal);
if (options.has(Options.CLASSES_INITIALIZATION))
cv = new ClinitInstrument(cv, options.value(Options.CLASSES_INITIALIZATION));
cv = new ClinitInstrument(cv, methodToLargestLocal, options.value(Options.CLASSES_INITIALIZATION));
if (options.has(Options.ALLOCATE) || options.has(Options.POINTER))
cv = new AllocateInstrument(cv, options.value(Options.ALLOCATE), options.has(Options.POINTER));
cv = new AllocateInstrument(cv, methodToLargestLocal, options.value(Options.ALLOCATE), options.has(Options.POINTER));
if (options.has(Options.CALL_CHAIN))
cv = new CallChainInstrument(cv);
cv = new CallChainInstrument(cv, methodToLargestLocal);
// The MethodInstrument is left out as there are a number of issues with
// instrumenting the bootclasses that I have not been able to resolve.
//
if (options.has(Options.METHOD_INSTR))
cv = new MethodInstrument(cv, reader.getClassName());
cv = new MethodInstrument(cv, methodToLargestLocal, reader.getClassName());
if (options.has(Options.LOG_START)) {
String startMethod = options.value(Options.LOG_START);
String stopMethod = options.value(Options.LOG_STOP);
if (stopMethod != null) {
cv = new LogInstrument(cv, startMethod, stopMethod);
cv = new LogInstrument(cv, methodToLargestLocal, startMethod, stopMethod);
} else {
cv = new LogInstrument(cv, startMethod);
cv = new LogInstrument(cv, methodToLargestLocal, startMethod);
}
}
......@@ -80,6 +109,12 @@ public class Instrument {
}
}
static int getArgumentSizes(int access, String desc) {
return
(((access & Opcodes.ACC_STATIC) == 0)?1:0) +
Type.getArgumentsAndReturnSizes(desc) >> 2;
}
private static ClassReader readClassFromFile(String infile) throws Exception {
FileInputStream is = null;
try {
......@@ -103,4 +138,65 @@ public class Instrument {
}
}
static String encodeMethodName(String klass, String method, String signature) {
return klass+"."+method+signature;
}
private static class LocalSizes extends ClassAdapter {
private TreeMap<String,Integer> methodToLargestLocal;
private boolean check;
private String name;
public LocalSizes(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal) {
super(cv);
this.methodToLargestLocal = methodToLargestLocal;
}
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
this.name = name;
this.check = (access & Opcodes.ACC_INTERFACE) == 0;
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (check && (access & (Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT))==0)
return new Maxs(access, this.name, name, desc, super.visitMethod(access, name, desc, signature, exceptions), methodToLargestLocal);
else
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
private static class Maxs extends AdviceAdapter {
public String encodedName;
public int maxLocals;
public int maxStack;
private TreeMap<String,Integer> methodToLargestLocal;
public Maxs(int access, String klass, String name, String desc, MethodVisitor mv, TreeMap<String,Integer> methodToLargestLocal) {
super(mv, access, name, desc);
this.encodedName = encodeMethodName(klass,name,desc);
this.maxLocals = getArgumentSizes(access, desc);
this.maxStack = 0;
this.methodToLargestLocal = methodToLargestLocal;
this.methodToLargestLocal.put(this.encodedName, new Integer(this.maxLocals));
}
public void visitVarInsn(int opcode, int var) {
if (this.maxLocals < var) {
this.maxLocals = var;
methodToLargestLocal.put(this.encodedName, new Integer(this.maxLocals));
}
super.visitVarInsn(opcode, var);
}
public void visitMaxs(int maxStack, int maxLocals) {
this.maxLocals = maxLocals;
if (this.maxLocals < maxStack) {
this.maxStack = maxStack;
methodToLargestLocal.put(encodedName, new Integer(this.maxLocals));
}
super.visitMaxs(maxStack, maxLocals);
}
}
}
package org.dacapo.instrument;
import java.util.TreeMap;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
......@@ -12,7 +14,7 @@ import org.objectweb.asm.commons.AdviceAdapter;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
public class LogInstrument extends ClassAdapter {
public class LogInstrument extends Instrument {
private static final String LOG_INTERNAL_NAME = "org/dacapo/instrument/Log";
private static final String LOG_METHOD_START = "start";
......@@ -41,12 +43,12 @@ public class LogInstrument extends ClassAdapter {
}
}
public LogInstrument(ClassVisitor cv, String logOn) {
this(cv,logOn,logOn);
public LogInstrument(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal, String logOn) {
this(cv,methodToLargestLocal,logOn,logOn);
}
public LogInstrument(ClassVisitor cv, String logOn, String logOff) {
super(cv);
public LogInstrument(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal, String logOn, String logOff) {
super(cv,methodToLargestLocal);
this.cv = cv;
this.logOnClass = getClassFrom(logOn);
this.logOnMethod = getMethodFrom(logOn);
......
......@@ -15,7 +15,7 @@ import org.objectweb.asm.commons.Method;
import java.util.TreeMap;
import java.util.Set;
public class MethodInstrument extends ClassAdapter {
public class MethodInstrument extends Instrument {
private static final int CLINIT_ACCESS = Opcodes.ACC_STATIC;
private static final String CLINIT_NAME = "<clinit>";
......@@ -46,8 +46,8 @@ public class MethodInstrument extends ClassAdapter {
private Method logBridgeMethod = null;
public MethodInstrument(ClassVisitor cv, String className) {
super(cv);
public MethodInstrument(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal, String className) {
super(cv, methodToLargestLocal);
this.cv = cv;
this.className = className;
}
......
......@@ -18,7 +18,7 @@ import org.objectweb.asm.commons.Method;
import org.objectweb.asm.commons.LocalVariablesSorter;
public class MonitorInstrument extends ClassAdapter {
public class MonitorInstrument extends Instrument {
private static final String LOG_INTERNAL_NAME = "org/dacapo/instrument/Log";
private static final String LOG_ENTER_METHOD = "reportMonitorEnter";
......@@ -45,8 +45,8 @@ public class MonitorInstrument extends ClassAdapter {
private boolean has_monitor_notify = true;
private boolean classDone = false;
public MonitorInstrument(ClassVisitor cv) {
super(cv);
public MonitorInstrument(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal) {
super(cv, methodToLargestLocal);
this.cv = cv;
}
......
package org.dacapo.instrument;
import java.util.TreeMap;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
......@@ -10,7 +12,7 @@ import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
public class RuntimeInstrument extends ClassAdapter {
public class RuntimeInstrument extends Instrument {
private static final String RUNTIME_CLASS_NAME = "java/lang/Runtime";
private static final String RUNTIME_METHOD_NAME = "availableProcessors";
......@@ -34,8 +36,8 @@ public class RuntimeInstrument extends ClassAdapter {
private boolean inherit;
private boolean overridden = false;
public RuntimeInstrument(ClassVisitor cv) {
super(cv);
public RuntimeInstrument(ClassVisitor cv, TreeMap<String,Integer> methodToLargestLocal) {
super(cv, methodToLargestLocal);
this.cv = cv;
}
......