8037082: java/lang/instrument/NativeMethodPrefixAgent.java failing

Reviewed-by: sla
This commit is contained in:
Jaroslav Bachorik 2014-08-25 18:17:24 +02:00
parent 34e103f04b
commit 82dd03274a
13 changed files with 253 additions and 2929 deletions

View File

@ -274,9 +274,6 @@ com/sun/jdi/JdbReadTwiceTest.sh generic-all
# jdk_instrument
# 8037082
java/lang/instrument/NativeMethodPrefixAgent.java generic-all
############################################################################
# svc_tools

View File

@ -75,9 +75,9 @@ JAR="${COMPILEJAVA}/bin/jar"
cp ${TESTSRC}/${AGENT}.java .
cp ${TESTSRC}/${APP}.java .
rm -rf ilib
mkdir ilib
cp ${TESTSRC}/ilib/*.java ilib
rm -rf asmlib
mkdir asmlib
cp ${TESTSRC}/asmlib/*.java asmlib
rm -rf bootpath
mkdir -p bootpath/bootreporter
cp ${TESTSRC}/bootreporter/*.java bootpath/bootreporter
@ -86,7 +86,7 @@ cd bootpath
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} bootreporter/*.java
cd ..
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${AGENT}.java ilib/*.java
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -XDignore.symbol.file ${AGENT}.java asmlib/*.java
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath .${PATHSEP}bootpath ${APP}.java
echo "Manifest-Version: 1.0" > ${AGENT}.mf
@ -98,6 +98,6 @@ while [ $# != 0 ] ; do
shift
done
${JAR} ${TESTTOOLVMOPTS} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class ilib/*.class
${JAR} ${TESTTOOLVMOPTS} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class asmlib/*.class
# rm -rf ${AGENT}.java ilib ${AGENT}.mf ${AGENT}*.class
# rm -rf ${AGENT}.java asmlib ${AGENT}.mf ${AGENT}*.class

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@ import java.lang.instrument.*;
import java.security.ProtectionDomain;
import java.io.*;
import ilib.*;
import asmlib.*;
class NativeMethodPrefixAgent {
@ -62,14 +62,25 @@ class NativeMethodPrefixAgent {
System.out.println(trname + ": " +
(redef? "Retransforming " : "Loading ") + className);
if (className != null) {
Options opt = new Options();
opt.shouldInstrumentNativeMethods = true;
opt.trackerClassName = "bootreporter/StringIdCallbackReporter";
opt.wrappedTrackerMethodName = "tracker";
opt.fixedIndex = transformId;
opt.wrappedPrefix = "wrapped_" + trname + "_";
try {
byte[] newcf = Inject.instrumentation(opt, loader, className, classfileBuffer);
byte[] newcf = Instrumentor.instrFor(classfileBuffer)
.addNativeMethodTrackingInjection(
"wrapped_" + trname + "_",
(h)->{
h.push(h.getName());
h.push(transformId);
h.invokeStatic("bootreporter/StringIdCallbackReporter", "tracker", "(Ljava/lang/String;I)V", false);
})
.apply();
/*** debugging ...
if (newcf != null) {
String fname = trname + (redef?"_redef" : "") + "/" + className;
System.err.println("dumping to: " + fname);
write_buffer(fname + "_before.class", classfileBuffer);
write_buffer(fname + "_instr.class", newcf);
}
***/
return redef? null : newcf;
} catch (Throwable ex) {
System.err.println("ERROR: Injection failure: " + ex);
@ -86,10 +97,14 @@ class NativeMethodPrefixAgent {
// for debugging
static void write_buffer(String fname, byte[]buffer) {
try {
FileOutputStream outStream = new FileOutputStream(fname);
outStream.write(buffer, 0, buffer.length);
outStream.close();
} catch (Exception ex) {
File f = new File(fname);
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
try (FileOutputStream outStream = new FileOutputStream(f)) {
outStream.write(buffer, 0, buffer.length);
}
} catch (IOException ex) {
System.err.println("EXCEPTION in write_buffer: " + ex);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,8 +34,7 @@
import java.lang.instrument.*;
import java.security.ProtectionDomain;
import java.io.*;
import ilib.*;
import asmlib.*;
class RetransformAgent {
@ -75,20 +74,25 @@ class RetransformAgent {
// System.err.println("hook " + trname + ": " + className +
// (redef? " REDEF" : " LOAD"));
if ((redef? onRedef : onLoad) && className != null && className.equals(cname)) {
Options opt = new Options();
opt.shouldInstrumentIndexed = true;
opt.shouldInstrumentCall = true;
opt.targetMethod = nname;
opt.fixedIndex = redef? redefIndex : loadIndex;
opt.trackerClassName = "RetransformAgent";
int fixedIndex = redef ? redefIndex : loadIndex;
try {
byte[] newcf = Inject.instrumentation(opt, loader, className, classfileBuffer);
byte[] newcf = Instrumentor.instrFor(classfileBuffer)
.addMethodEntryInjection(
nname,
(h)->{
h.push(fixedIndex);
h.invokeStatic("RetransformAgent", "callTracker", "(I)V", false);
})
.apply();
/*** debugging ...
String fname = trname + (redef?"_redef" : "");
write_buffer(fname + "_before.class", classfileBuffer);
write_buffer(fname + "_instr.class", newcf);
if (newcf != null) {
String fname = trname + (redef?"_redef" : "") + "/" + className;
System.err.println("dumping to: " + fname);
write_buffer(fname + "_before.class", classfileBuffer);
write_buffer(fname + "_instr.class", newcf);
}
***/
System.err.println(trname + ": " + className + " index: " + opt.fixedIndex +
System.err.println(trname + ": " + className + " index: " + fixedIndex +
(redef? " REDEF" : " LOAD") +
" len before: " + classfileBuffer.length +
" after: " + newcf.length);
@ -104,10 +108,14 @@ class RetransformAgent {
static void write_buffer(String fname, byte[]buffer) {
try {
FileOutputStream outStream = new FileOutputStream(fname);
outStream.write(buffer, 0, buffer.length);
outStream.close();
} catch (Exception ex) {
File f = new File(fname);
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
try (FileOutputStream outStream = new FileOutputStream(f)) {
outStream.write(buffer, 0, buffer.length);
}
} catch (IOException ex) {
System.err.println("EXCEPTION in write_buffer: " + ex);
}
}

View File

@ -0,0 +1,193 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package asmlib;
import java.io.PrintStream;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import java.util.function.Consumer;
import jdk.internal.org.objectweb.asm.Type;
public class Instrumentor {
public static class InstrHelper {
private final MethodVisitor mv;
private final String name;
InstrHelper(MethodVisitor mv, String name) {
this.mv = mv;
this.name = name;
}
public String getName() {
return this.name;
}
public void invokeStatic(String owner, String name, String desc, boolean itf) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf);
}
public void invokeSpecial(String owner, String name, String desc) {
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false);
}
public void invokeVirtual(String owner, String name, String desc) {
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
}
public void push(int val) {
if (val >= -1 && val <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + val);
} else if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, val);
} else if (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, val);
} else {
mv.visitLdcInsn(val);
}
}
public void push(Object val) {
mv.visitLdcInsn(val);
}
public void println(String s) {
mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(System.class), "out", Type.getDescriptor(PrintStream.class));
mv.visitLdcInsn(s);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(PrintStream.class), "println", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false);
}
}
public static Instrumentor instrFor(byte[] classData) {
return new Instrumentor(classData);
}
private final ClassReader cr;
private final ClassWriter output;
private ClassVisitor instrumentingVisitor = null;
private final AtomicInteger matches = new AtomicInteger(0);
private Instrumentor(byte[] classData) {
cr = new ClassReader(classData);
output = new ClassWriter(ClassWriter.COMPUTE_MAXS);
instrumentingVisitor = output;
}
public synchronized Instrumentor addMethodEntryInjection(String methodName, Consumer<InstrHelper> injector) {
instrumentingVisitor = new ClassVisitor(Opcodes.ASM5, instrumentingVisitor) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (name.equals(methodName)) {
matches.getAndIncrement();
mv = new MethodVisitor(Opcodes.ASM5, mv) {
@Override
public void visitCode() {
injector.accept(new InstrHelper(mv, name));
}
};
}
return mv;
}
};
return this;
}
public synchronized Instrumentor addNativeMethodTrackingInjection(String prefix, Consumer<InstrHelper> injector) {
instrumentingVisitor = new ClassVisitor(Opcodes.ASM5, instrumentingVisitor) {
private final Set<Consumer<ClassVisitor>> wmGenerators = new HashSet<>();
private String className;
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
this.className = name;
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if ((access & Opcodes.ACC_NATIVE) != 0) {
matches.getAndIncrement();
String newName = prefix + name;
wmGenerators.add((v)->{
MethodVisitor mv = v.visitMethod(access & ~Opcodes.ACC_NATIVE, name, desc, signature, exceptions);
mv.visitCode();
injector.accept(new InstrHelper(mv, name));
Type[] argTypes = Type.getArgumentTypes(desc);
Type retType = Type.getReturnType(desc);
boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
if (!isStatic) {
mv.visitIntInsn(Opcodes.ALOAD, 0); // load "this"
}
// load the method parameters
if (argTypes.length > 0) {
int ptr = isStatic ? 0 : 1;
for(Type argType : argTypes) {
mv.visitIntInsn(argType.getOpcode(Opcodes.ILOAD), ptr);
ptr += argType.getSize();
}
}
mv.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKESPECIAL, className, newName, desc, false);
mv.visitInsn(retType.getOpcode(Opcodes.IRETURN));
mv.visitMaxs(1, 1); // dummy call; let ClassWriter to deal with this
mv.visitEnd();
});
return super.visitMethod(access, newName, desc, signature, exceptions);
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
@Override
public void visitEnd() {
wmGenerators.stream().forEach((e) -> {
e.accept(cv);
});
super.visitEnd();
}
};
return this;
}
public synchronized byte[] apply() {
cr.accept(instrumentingVisitor, ClassReader.SKIP_DEBUG + ClassReader.EXPAND_FRAMES);
return matches.get() == 0 ? null : output.toByteArray();
}
}

View File

@ -1,273 +0,0 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package ilib;
import java.io.IOException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.CharArrayWriter;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
public class ClassDump implements RuntimeConstants {
public static void dump(Options opt,
ClassLoader loader,
String className,
byte[] classfileBuffer) {
ClassReaderWriter c = new ClassReaderWriter(classfileBuffer);
(new ClassDump(className, c)).doit();
}
static boolean verbose = true;
final String className;
final ClassReaderWriter c;
private final PrintStream output;
int constantPoolCount;
int methodsCount;
ClassDump(String className, ClassReaderWriter c) {
this.className = className;
this.c = c;
this.output = System.err;
}
void doit() {
int i;
c.copy(4 + 2 + 2); // magic min/maj version
constantPoolCount = c.copyU2();
// copy old constant pool
c.copyConstantPool(constantPoolCount);
traceln("ConstantPool size: " + constantPoolCount);
c.copy(2 + 2 + 2); // access, this, super
int interfaceCount = c.copyU2();
traceln("interfaceCount: " + interfaceCount);
c.copy(interfaceCount * 2);
copyFields(); // fields
copyMethods(); // methods
int attrCount = c.copyU2();
traceln("class attrCount: " + attrCount);
// copy the class attributes
copyAttrs(attrCount);
}
void copyFields() {
int count = c.copyU2();
if (verbose) {
System.out.println("fields count: " + count);
}
for (int i = 0; i < count; ++i) {
c.copy(6); // access, name, descriptor
int attrCount = c.copyU2();
if (verbose) {
System.out.println("field attr count: " + attrCount);
}
copyAttrs(attrCount);
}
}
void copyMethods() {
methodsCount = c.copyU2();
if (verbose) {
System.out.println("methods count: " + methodsCount);
}
for (int i = 0; i < methodsCount; ++i) {
copyMethod();
}
}
void copyMethod() {
int accessFlags = c.copyU2();// access flags
int nameIndex = c.copyU2(); // name
checkIndex(nameIndex, "Method name");
String methodName = c.constantPoolString(nameIndex);
traceln("method: " + methodName);
int descriptorIndex = c.copyU2(); // descriptor
checkIndex(descriptorIndex, "Method descriptor");
int attrCount = c.copyU2(); // attribute count
if (verbose) {
System.out.println("method attr count: " + attrCount);
}
for (int i = 0; i < attrCount; ++i) {
copyAttrForMethod(methodName, accessFlags);
}
}
void copyAttrs(int attrCount) {
for (int i = 0; i < attrCount; ++i) {
copyAttr();
}
}
void copyAttr() {
c.copy(2); // name
int len = c.copyU4(); // attr len
if (verbose) {
System.out.println("attr len: " + len);
}
c.copy(len); // attribute info
}
void copyAttrForMethod(String methodName, int accessFlags) {
int nameIndex = c.copyU2(); // name
// check for Code attr
checkIndex(nameIndex, "Method attr name");
if (nameIndex == c.codeAttributeIndex) {
try {
copyCodeAttr(methodName);
} catch (IOException exc) {
System.err.println("Code Exception - " + exc);
System.exit(1);
}
} else {
int len = c.copyU4(); // attr len
traceln("method attr len: " + len);
c.copy(len); // attribute info
}
}
void copyAttrForCode() throws IOException {
int nameIndex = c.copyU2(); // name
checkIndex(nameIndex, "Code attr name");
int len = c.copyU4(); // attr len
traceln("code attr len: " + len);
c.copy(len); // attribute info
}
void copyCodeAttr(String methodName) throws IOException {
traceln("Code attr found");
int attrLength = c.copyU4(); // attr len
checkLength(attrLength, "Code attr length");
int maxStack = c.readU2(); // max stack
c.copyU2(); // max locals
int codeLength = c.copyU4(); // code length
checkLength(codeLength, "Code length");
copyExceptionTable();
int attrCount = c.copyU2();
checkLength(attrCount, "Code attr count");
for (int i = 0; i < attrCount; ++i) {
copyAttrForCode();
}
}
/**
* Copy the exception table for this method code
*/
void copyExceptionTable() throws IOException {
int tableLength = c.copyU2(); // exception table len
checkLength(tableLength, "Exception Table length");
if (tableLength > 0) {
traceln();
traceln("Exception table:");
traceln(" from:old/new to:old/new target:old/new type");
for (int tcnt = tableLength; tcnt > 0; --tcnt) {
int startPC = c.readU2();
int endPC = c.readU2();
int handlerPC = c.readU2();
int catchType = c.copyU2();
if (verbose) {
traceFixedWidthInt(startPC, 6);
traceFixedWidthInt(endPC, 6);
traceFixedWidthInt(handlerPC, 6);
trace(" ");
if (catchType == 0)
traceln("any");
else {
traceln("" + catchType);
}
}
}
}
}
private void checkIndex(int index, String comment) {
if (index > constantPoolCount) {
output.println("ERROR BAD INDEX " + comment + " : " + index);
} else {
traceln(comment + " : " + index);
}
}
private void checkLength(int length, String comment) {
if (length > c.inputBytes().length) {
output.println("ERROR BAD LENGTH " + comment + " : " + length);
} else {
traceln(comment + " : " + length);
}
}
private void trace(String str) {
if (verbose) {
output.print(str);
}
}
private void traceln(String str) {
if (verbose) {
output.println(str);
}
}
private void traceln() {
if (verbose) {
output.println();
}
}
private void trace(int i) {
if (verbose) {
output.print(i);
}
}
/**
* Print an integer so that it takes 'length' characters in
* the output. Temporary until formatting code is stable.
*/
private void traceFixedWidthInt(int x, int length) {
if (verbose) {
CharArrayWriter baStream = new CharArrayWriter();
PrintWriter pStream = new PrintWriter(baStream);
pStream.print(x);
String str = baStream.toString();
for (int cnt = length - str.length(); cnt > 0; --cnt)
trace(" ");
trace(str);
}
}
}

View File

@ -1,263 +0,0 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package ilib;
class ClassReaderWriter implements RuntimeConstants {
int codeAttributeIndex;
int lineNumberAttributeIndex;
int localVarAttributeIndex;
private final byte[] orig;
private final byte[] gen;
private final int sectionLength;
private static final int GROWTH_FACTOR = 2;
private static final int SECTIONS = 2;
private static final String codeAttributeName = "Code";
private static final String lineNumberAttributeName = "LineNumberTable";
private static final String localVarAttributeName = "LocalVariableTable";
private int[] genSectionPos = new int[SECTIONS];
private int inputPos = 0;
private int genPos = 0;
private int markPos = 0;
private int currentSection = 0;
private String[] constantPool;
ClassReaderWriter(byte[] orig) {
this.orig = orig;
sectionLength = orig.length * GROWTH_FACTOR;
gen = new byte[sectionLength * SECTIONS];
for (int section = 0; section < SECTIONS; ++section) {
genSectionPos[section] = section * sectionLength;
}
}
int setSection(int section) {
int prevSection = currentSection;
genSectionPos[prevSection] = genPos;
genPos = genSectionPos[section];
currentSection = section;
return prevSection;
}
byte[] result() {
int section;
int totalLength = 0;
setSection(0); // save current section
for (section = 0; section < SECTIONS; ++section) {
int sectionStart = section * sectionLength;
int sectionGenLength = genSectionPos[section] - sectionStart;
totalLength += sectionGenLength;
}
byte[] newcf = new byte[totalLength];
int written = 0;
for (section = 0; section < SECTIONS; ++section) {
int sectionStart = section * sectionLength;
int sectionGenLength = genSectionPos[section] - sectionStart;
System.arraycopy(gen, sectionStart, newcf, written, sectionGenLength);
written += sectionGenLength;
}
return newcf;
}
int readU1() {
return ((int)orig[inputPos++]) & 0xFF;
}
int readU2() {
int res = readU1();
return (res << 8) + readU1();
}
short readS2() {
int res = readU1();
return (short)((res << 8) + readU1());
}
int readU4() {
int res = readU2();
return (res << 16) + readU2();
}
void writeU1(int val) {
gen[genPos++] = (byte)val;
}
void writeU2(int val) {
writeU1(val >> 8);
writeU1(val & 0xFF);
}
void writeU4(int val) {
writeU2(val >> 16);
writeU2(val & 0xFFFF);
}
int copyU1() {
int value = readU1();
writeU1(value);
return value;
}
int copyU2() {
int value = readU2();
writeU2(value);
return value;
}
int copyU4() {
int value = readU4();
writeU4(value);
return value;
}
void copy(int count) {
for (int i = 0; i < count; ++i) {
gen[genPos++] = orig[inputPos++];
}
}
void skip(int count) {
inputPos += count;
}
byte[] readBytes(int count) {
byte[] bytes = new byte[count];
for (int i = 0; i < count; ++i) {
bytes[i] = orig[inputPos++];
}
return bytes;
}
void writeBytes(byte[] bytes) {
for (int i = 0; i < bytes.length; ++i) {
gen[genPos++] = bytes[i];
}
}
byte[] inputBytes() {
return orig;
}
int inputPosition() {
return inputPos;
}
void setInputPosition(int pos) {
inputPos = pos;
}
void markLocalPositionStart() {
markPos = inputPos;
}
int localPosition() {
return inputPos - markPos;
}
void rewind() {
setInputPosition(markPos);
}
int generatedPosition() {
return genPos;
}
void randomAccessWriteU2(int pos, int val) {
int savePos = genPos;
genPos = pos;
writeU2(val);
genPos = savePos;
}
void randomAccessWriteU4(int pos, int val) {
int savePos = genPos;
genPos = pos;
writeU4(val);
genPos = savePos;
}
String constantPoolString(int index) {
return constantPool[index];
}
void copyConstantPool(int constantPoolCount){
// copy const pool
constantPool = new String[constantPoolCount];
// index zero not in class file
for (int i = 1; i < constantPoolCount; ++i) {
int tag = readU1();
writeU1(tag);
switch (tag) {
case CONSTANT_CLASS:
case CONSTANT_STRING:
copy(2);
break;
case CONSTANT_FIELD:
case CONSTANT_METHOD:
case CONSTANT_INTERFACEMETHOD:
case CONSTANT_INTEGER:
case CONSTANT_FLOAT:
case CONSTANT_NAMEANDTYPE:
copy(4);
break;
case CONSTANT_LONG:
case CONSTANT_DOUBLE:
copy(8);
++i; // these take two CP entries - duh!
break;
case CONSTANT_UTF8:
int len = copyU2();
byte[] utf8 = readBytes(len);
String str = null; // null to shut the compiler up
try {
str = new String(utf8, "UTF-8");
} catch (Exception exc) {
throw new Error("CP exception: " + exc);
}
constantPool[i] = str;
if (str.equals(codeAttributeName)) {
codeAttributeIndex = i;
} else if (str.equals(lineNumberAttributeName)) {
lineNumberAttributeIndex = i;
} else if (str.equals(localVarAttributeName)) {
localVarAttributeIndex = i;
}
writeBytes(utf8);
break;
default:
throw new Error(i + " unexpected CP tag: " + tag);
}
}
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package ilib;
public class Info {
final int counter;
final String className;
final String methodName;
final int location;
Info(int counter, String className, String methodName, int location) {
this.counter = counter;
this.className = className;
this.methodName = methodName;
this.location = location;
}
}

View File

@ -1,746 +0,0 @@
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package ilib;
import java.io.IOException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
public class Inject implements RuntimeConstants {
public static byte[] instrumentation(Options opt,
ClassLoader loader,
String className,
byte[] classfileBuffer) {
ClassReaderWriter c = new ClassReaderWriter(classfileBuffer);
(new Inject(className, c, loader == null, opt)).doit();
return c.result();
}
static boolean verbose = false;
final String className;
final ClassReaderWriter c;
final boolean isSystem;
final Options options;
int constantPoolCount;
int methodsCount;
int methodsCountPos;
int profiler;
int wrappedTrackerIndex = 0;
int thisClassIndex = 0;
TrackerInjector callInjector;
TrackerInjector allocInjector;
TrackerInjector defaultInjector;
static interface TrackerInjector extends Injector {
void reinit(int tracker);
int stackSize(int currentSize);
}
static class SimpleInjector implements TrackerInjector {
byte[] injection;
public int stackSize(int currentSize) {
return currentSize;
}
public void reinit(int tracker) {
injection = new byte[3];
injection[0] = (byte)opc_invokestatic;
injection[1] = (byte)(tracker >> 8);
injection[2] = (byte)tracker;
}
public byte[] bytecodes(String className, String methodName, int location) {
return injection;
}
}
static class ObjectInjector implements TrackerInjector {
byte[] injection;
public int stackSize(int currentSize) {
return currentSize + 1;
}
public void reinit(int tracker) {
injection = new byte[4];
injection[0] = (byte)opc_dup;
injection[1] = (byte)opc_invokestatic;
injection[2] = (byte)(tracker >> 8);
injection[3] = (byte)tracker;
}
public byte[] bytecodes(String className, String methodName, int location) {
return injection;
}
}
class IndexedInjector implements TrackerInjector {
int counter = 0;
int tracker;
List<Info> infoList = new ArrayList<>();
public int stackSize(int currentSize) {
return currentSize + 1;
}
public void reinit(int tracker) {
this.tracker = tracker;
}
void dump(File outDir, String filename) throws IOException {
try (FileOutputStream fileOut =
new FileOutputStream(new File(outDir, filename));
DataOutputStream dataOut = new DataOutputStream(fileOut))
{
String currentClassName = null;
dataOut.writeInt(infoList.size());
for (Iterator<Info> it = infoList.iterator(); it.hasNext(); ) {
Info info = it.next();
if (!info.className.equals(currentClassName)) {
dataOut.writeInt(123456); // class name marker
currentClassName = info.className;
dataOut.writeUTF(currentClassName);
}
dataOut.writeInt(info.location);
dataOut.writeUTF(info.methodName);
}
}
}
public byte[] bytecodes(String className, String methodName, int location) {
byte[] injection = new byte[6];
int injectedIndex = options.fixedIndex != 0? options.fixedIndex : ++counter;
infoList.add(new Info(counter, className, methodName, location));
injection[0] = (byte)opc_sipush;
injection[1] = (byte)(injectedIndex >> 8);
injection[2] = (byte)injectedIndex;
injection[3] = (byte)opc_invokestatic;
injection[4] = (byte)(tracker >> 8);
injection[5] = (byte)tracker;
return injection;
}
}
Inject(String className, ClassReaderWriter c, boolean isSystem, Options options) {
this.className = className;
this.c = c;
this.isSystem = isSystem;
this.options = options;
}
void doit() {
int i;
c.copy(4 + 2 + 2); // magic min/maj version
int constantPoolCountPos = c.generatedPosition();
constantPoolCount = c.copyU2();
// copy old constant pool
c.copyConstantPool(constantPoolCount);
if (verbose) {
System.out.println("ConstantPool expanded from: " +
constantPoolCount);
}
profiler = addClassToConstantPool(options.trackerClassName);
if (options.shouldInstrumentNew || options.shouldInstrumentObjectInit) {
if (options.shouldInstrumentIndexed) {
if (allocInjector == null) {
// first time - create it
allocInjector = new IndexedInjector();
}
int allocTracker = addMethodToConstantPool(profiler,
options.allocTrackerMethodName,
"(I)V");
allocInjector.reinit(allocTracker);
} else if (options.shouldInstrumentObject) {
if (allocInjector == null) {
// first time - create it
allocInjector = new ObjectInjector();
}
int allocTracker = addMethodToConstantPool(profiler,
options.allocTrackerMethodName,
"(Ljava/lang/Object;)V");
allocInjector.reinit(allocTracker);
} else {
if (allocInjector == null) {
// first time - create it
allocInjector = new SimpleInjector();
}
int allocTracker = addMethodToConstantPool(profiler,
options.allocTrackerMethodName,
"()V");
allocInjector.reinit(allocTracker);
}
defaultInjector = allocInjector;
}
if (options.shouldInstrumentCall) {
if (options.shouldInstrumentIndexed) {
if (callInjector == null) {
// first time - create it
callInjector = new IndexedInjector();
}
int callTracker = addMethodToConstantPool(profiler,
options.callTrackerMethodName,
"(I)V");
callInjector.reinit(callTracker);
} else {
if (callInjector == null) {
// first time - create it
callInjector = new SimpleInjector();
}
int callTracker = addMethodToConstantPool(profiler,
options.callTrackerMethodName,
"()V");
callInjector.reinit(callTracker);
}
defaultInjector = callInjector;
}
if (verbose) {
System.out.println("To: " + constantPoolCount);
}
c.setSection(1);
c.copy(2 + 2 + 2); // access, this, super
int interfaceCount = c.copyU2();
if (verbose) {
System.out.println("interfaceCount: " + interfaceCount);
}
c.copy(interfaceCount * 2);
copyFields(); // fields
copyMethods(); // methods
int attrCountPos = c.generatedPosition();
int attrCount = c.copyU2();
if (verbose) {
System.out.println("class attrCount: " + attrCount);
}
// copy the class attributes
copyAttrs(attrCount);
c.randomAccessWriteU2(constantPoolCountPos, constantPoolCount);
}
void copyFields() {
int count = c.copyU2();
if (verbose) {
System.out.println("fields count: " + count);
}
for (int i = 0; i < count; ++i) {
c.copy(6); // access, name, descriptor
int attrCount = c.copyU2();
if (verbose) {
System.out.println("field attr count: " + attrCount);
}
copyAttrs(attrCount);
}
}
void copyMethods() {
methodsCountPos = c.generatedPosition();
methodsCount = c.copyU2();
int initialMethodsCount = methodsCount;
if (verbose) {
System.out.println("methods count: " + methodsCount);
}
for (int i = 0; i < initialMethodsCount; ++i) {
copyMethod();
}
}
void copyMethod() {
int accessFlags = c.copyU2();// access flags
if (options.shouldInstrumentNativeMethods && (accessFlags & ACC_NATIVE) != 0) {
wrapNativeMethod(accessFlags);
return;
}
int nameIndex = c.copyU2(); // name
String methodName = c.constantPoolString(nameIndex);
c.copyU2(); // descriptor
int attrCount = c.copyU2(); // attribute count
if (verbose) {
System.out.println("methods attr count: " + attrCount);
}
for (int i = 0; i < attrCount; ++i) {
copyAttrForMethod(methodName, accessFlags);
}
}
void wrapNativeMethod(int accessFlags) {
// first, copy the native method with the name changed
// accessFlags have already been copied
int nameIndex = c.readU2(); // name
String methodName = c.constantPoolString(nameIndex);
String wrappedMethodName = options.wrappedPrefix + methodName;
int wrappedNameIndex = writeCPEntryUtf8(wrappedMethodName);
c.writeU2(wrappedNameIndex); // change to the wrapped name
int descriptorIndex = c.copyU2(); // descriptor index
int attrCount = c.copyU2(); // attribute count
// need to replicate these attributes (esp Exceptions) in wrapper
// so mark this location so we can rewind
c.markLocalPositionStart();
for (int i = 0; i < attrCount; ++i) {
copyAttrForMethod(methodName, accessFlags);
}
if (true) {
System.err.println(" wrapped: " + methodName);
}
// now write the wrapper method
c.writeU2(accessFlags & ~ACC_NATIVE);
c.writeU2(nameIndex); // original unwrapped name
c.writeU2(descriptorIndex); // descriptor is the same
c.writeU2(attrCount + 1); // wrapped plus a code attribute
// rewind to wrapped attributes
c.rewind();
for (int i = 0; i < attrCount; ++i) {
copyAttrForMethod(methodName, accessFlags);
}
// generate a Code attribute for the wrapper method
int wrappedIndex = addMethodToConstantPool(getThisClassIndex(),
wrappedNameIndex,
descriptorIndex);
String descriptor = c.constantPoolString(descriptorIndex);
createWrapperCodeAttr(nameIndex, accessFlags, descriptor, wrappedIndex);
// increment method count
c.randomAccessWriteU2(methodsCountPos, ++methodsCount);
}
void copyAttrs(int attrCount) {
for (int i = 0; i < attrCount; ++i) {
copyAttr();
}
}
void copyAttr() {
c.copy(2); // name
int len = c.copyU4(); // attr len
if (verbose) {
System.out.println("attr len: " + len);
}
c.copy(len); // attribute info
}
void copyAttrForMethod(String methodName, int accessFlags) {
int nameIndex = c.copyU2(); // name
// check for Code attr
if (nameIndex == c.codeAttributeIndex) {
try {
copyCodeAttr(methodName);
} catch (IOException exc) {
System.err.println("Code Exception - " + exc);
System.exit(1);
}
} else {
int len = c.copyU4(); // attr len
if (verbose) {
System.out.println("method attr len: " + len);
}
c.copy(len); // attribute info
}
}
void copyAttrForCode(InjectBytecodes ib) throws IOException {
int nameIndex = c.copyU2(); // name
// check for Code attr
if (nameIndex == c.lineNumberAttributeIndex) {
ib.copyLineNumberAttr();
} else if (nameIndex == c.localVarAttributeIndex) {
ib.copyLocalVarAttr();
} else {
int len = c.copyU4(); // attr len
if (verbose) {
System.out.println("code attr len: " + len);
}
c.copy(len); // attribute info
}
}
void copyCodeAttr(String methodName) throws IOException {
if (verbose) {
System.out.println("Code attr found");
}
int attrLengthPos = c.generatedPosition();
int attrLength = c.copyU4(); // attr len
int maxStack = c.readU2(); // max stack
c.writeU2(defaultInjector == null? maxStack :
defaultInjector.stackSize(maxStack)); // big enough for injected code
c.copyU2(); // max locals
int codeLengthPos = c.generatedPosition();
int codeLength = c.copyU4(); // code length
if (options.targetMethod != null && !options.targetMethod.equals(methodName)) {
c.copy(attrLength - 8); // copy remainder minus already copied
return;
}
if (isSystem) {
if (codeLength == 1 && methodName.equals("finalize")) {
if (verbose) {
System.out.println("empty system finalizer not instrumented");
}
c.copy(attrLength - 8); // copy remainder minus already copied
return;
}
if (codeLength == 1 && methodName.equals("<init>")) {
if (verbose) {
System.out.println("empty system constructor not instrumented");
}
if (!options.shouldInstrumentObjectInit) {
c.copy(attrLength - 8); // copy remainder minus already copied
return;
}
}
if (methodName.equals("<clinit>")) {
if (verbose) {
System.out.println("system class initializer not instrumented");
}
c.copy(attrLength - 8); // copy remainder minus already copied
return;
}
}
if (options.shouldInstrumentObjectInit
&& (!className.equals("java/lang/Object")
|| !methodName.equals("<init>"))) {
c.copy(attrLength - 8); // copy remainder minus already copied
return;
}
InjectBytecodes ib = new InjectBytecodes(c, codeLength, className, methodName);
if (options.shouldInstrumentNew) {
ib.injectAfter(opc_new, allocInjector);
ib.injectAfter(opc_newarray, allocInjector);
ib.injectAfter(opc_anewarray, allocInjector);
ib.injectAfter(opc_multianewarray, allocInjector);
}
if (options.shouldInstrumentCall) {
ib.inject(0, callInjector.bytecodes(className, methodName, 0));
}
if (options.shouldInstrumentObjectInit) {
ib.inject(0, allocInjector.bytecodes(className, methodName, 0));
}
ib.adjustOffsets();
// fix up code length
int newCodeLength = c.generatedPosition() - (codeLengthPos + 4);
c.randomAccessWriteU4(codeLengthPos, newCodeLength);
if (verbose) {
System.out.println("code length old: " + codeLength +
", new: " + newCodeLength);
}
ib.copyExceptionTable();
int attrCount = c.copyU2();
for (int i = 0; i < attrCount; ++i) {
copyAttrForCode(ib);
}
// fix up attr length
int newAttrLength = c.generatedPosition() - (attrLengthPos + 4);
c.randomAccessWriteU4(attrLengthPos, newAttrLength);
if (verbose) {
System.out.println("attr length old: " + attrLength +
", new: " + newAttrLength);
}
}
int nextDescriptorIndex(String descriptor, int index) {
switch (descriptor.charAt(index)) {
case 'B': // byte
case 'C': // char
case 'I': // int
case 'S': // short
case 'Z': // boolean
case 'F': // float
case 'D': // double
case 'J': // long
return index + 1;
case 'L': // object
int i = index + 1;
while (descriptor.charAt(i) != ';') {
++i;
}
return i + 1;
case '[': // array
return nextDescriptorIndex(descriptor, index + 1);
}
throw new InternalError("should not reach here");
}
int getWrappedTrackerIndex() {
if (wrappedTrackerIndex == 0) {
wrappedTrackerIndex = addMethodToConstantPool(profiler,
options.wrappedTrackerMethodName,
"(Ljava/lang/String;I)V");
}
return wrappedTrackerIndex;
}
int getThisClassIndex() {
if (thisClassIndex == 0) {
thisClassIndex = addClassToConstantPool(className);
}
return thisClassIndex;
}
int computeMaxLocals(String descriptor, int accessFlags) {
int index = 1;
int slot = 0;
if ((accessFlags & ACC_STATIC) == 0) {
++slot;
}
char type;
while ((type = descriptor.charAt(index)) != ')') {
switch (type) {
case 'B': // byte
case 'C': // char
case 'I': // int
case 'S': // short
case 'Z': // boolean
case 'F': // float
case 'L': // object
case '[': // array
++slot;
break;
case 'D': // double
case 'J': // long
slot += 2;
break;
}
index = nextDescriptorIndex(descriptor, index);
}
return slot;
}
void createWrapperCodeAttr(int methodNameIndex, int accessFlags,
String descriptor, int wrappedIndex) {
int maxLocals = computeMaxLocals(descriptor, accessFlags);
c.writeU2(c.codeAttributeIndex); //
int attrLengthPos = c.generatedPosition();
c.writeU4(0); // attr len -- fix up below
c.writeU2(maxLocals + 4); // max stack
c.writeU2(maxLocals); // max locals
int codeLengthPos = c.generatedPosition();
c.writeU4(0); // code length -- fix up below
int methodStringIndex = writeCPEntryString(methodNameIndex);
c.writeU1(opc_ldc_w);
c.writeU2(methodStringIndex); // send the method name
c.writeU1(opc_sipush);
c.writeU2(options.fixedIndex);
c.writeU1(opc_invokestatic);
c.writeU2(getWrappedTrackerIndex());
// set-up args
int index = 1;
int slot = 0;
if ((accessFlags & ACC_STATIC) == 0) {
c.writeU1(opc_aload_0); // this
++slot;
}
char type;
while ((type = descriptor.charAt(index)) != ')') {
switch (type) {
case 'B': // byte
case 'C': // char
case 'I': // int
case 'S': // short
case 'Z': // boolean
c.writeU1(opc_iload);
c.writeU1(slot);
++slot;
break;
case 'F': // float
c.writeU1(opc_fload);
c.writeU1(slot);
++slot;
break;
case 'D': // double
c.writeU1(opc_dload);
c.writeU1(slot);
slot += 2;
break;
case 'J': // long
c.writeU1(opc_lload);
c.writeU1(slot);
slot += 2;
break;
case 'L': // object
case '[': // array
c.writeU1(opc_aload);
c.writeU1(slot);
++slot;
break;
}
index = nextDescriptorIndex(descriptor, index);
}
// call the wrapped version
if ((accessFlags & ACC_STATIC) == 0) {
c.writeU1(opc_invokevirtual);
} else {
c.writeU1(opc_invokestatic);
}
c.writeU2(wrappedIndex);
// return correct type
switch (descriptor.charAt(index+1)) {
case 'B': // byte
case 'C': // char
case 'I': // int
case 'S': // short
case 'Z': // boolean
c.writeU1(opc_ireturn);
break;
case 'F': // float
c.writeU1(opc_freturn);
break;
case 'D': // double
c.writeU1(opc_dreturn);
break;
case 'J': // long
c.writeU1(opc_lreturn);
break;
case 'L': // object
case '[': // array
c.writeU1(opc_areturn);
break;
case 'V': // void
c.writeU1(opc_return);
break;
}
// end of code
// fix up code length
int newCodeLength = c.generatedPosition() - (codeLengthPos + 4);
c.randomAccessWriteU4(codeLengthPos, newCodeLength);
c.writeU2(0); // exception table length
c.writeU2(0); // attribute count
// fix up attr length
int newAttrLength = c.generatedPosition() - (attrLengthPos + 4);
c.randomAccessWriteU4(attrLengthPos, newAttrLength);
}
int addClassToConstantPool(String className) {
int prevSection = c.setSection(0);
int classNameIndex = writeCPEntryUtf8(className);
int classIndex = writeCPEntryClass(classNameIndex);
c.setSection(prevSection);
return classIndex;
}
int addMethodToConstantPool(int classIndex,
String methodName,
String descr) {
int prevSection = c.setSection(0);
int methodNameIndex = writeCPEntryUtf8(methodName);
int descrIndex = writeCPEntryUtf8(descr);
c.setSection(prevSection);
return addMethodToConstantPool(classIndex, methodNameIndex, descrIndex);
}
int addMethodToConstantPool(int classIndex,
int methodNameIndex,
int descrIndex) {
int prevSection = c.setSection(0);
int nameAndTypeIndex = writeCPEntryNameAndType(methodNameIndex,
descrIndex);
int methodIndex = writeCPEntryMethodRef(classIndex, nameAndTypeIndex);
c.setSection(prevSection);
return methodIndex;
}
int writeCPEntryUtf8(String str) {
int prevSection = c.setSection(0);
int len = str.length();
c.writeU1(CONSTANT_UTF8); // Utf8 tag
c.writeU2(len);
for (int i = 0; i < len; ++i) {
c.writeU1(str.charAt(i));
}
c.setSection(prevSection);
return constantPoolCount++;
}
int writeCPEntryString(int utf8Index) {
int prevSection = c.setSection(0);
c.writeU1(CONSTANT_STRING);
c.writeU2(utf8Index);
c.setSection(prevSection);
return constantPoolCount++;
}
int writeCPEntryClass(int classNameIndex) {
int prevSection = c.setSection(0);
c.writeU1(CONSTANT_CLASS);
c.writeU2(classNameIndex);
c.setSection(prevSection);
return constantPoolCount++;
}
int writeCPEntryNameAndType(int nameIndex, int descrIndex) {
int prevSection = c.setSection(0);
c.writeU1(CONSTANT_NAMEANDTYPE);
c.writeU2(nameIndex);
c.writeU2(descrIndex);
c.setSection(prevSection);
return constantPoolCount++;
}
int writeCPEntryMethodRef(int classIndex, int nameAndTypeIndex) {
int prevSection = c.setSection(0);
c.writeU1(CONSTANT_METHOD);
c.writeU2(classIndex);
c.writeU2(nameAndTypeIndex);
c.setSection(prevSection);
return constantPoolCount++;
}
}

View File

@ -1,769 +0,0 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* An extension of BinaryCode that allows code to be printed.
* Includes printing of disassembled byte codes, exception info,
* local variable and line number info.
*
*/
package ilib;
import java.io.ByteArrayInputStream;
import java.io.CharArrayWriter;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.PrintStream;
import java.util.Map;
import java.util.HashMap;
class InjectBytecodes implements RuntimeConstants {
private final ClassReaderWriter c;
private final PrintStream output;
private final int length;
private final int[] map;
private final byte[] widening;
private final Injector[] before = new Injector[256];
private final Injector[] after = new Injector[256];
private final String className;
private final String methodName;
private final Map<Integer,byte[]> snippets = new HashMap<>();
private int pos;
private int newPos;
private class Span {
final int delta;
final int target;
final int newDelta;
final int newTarget;
Span(int delta) {
this.delta = delta;
this.target = pos + delta;
this.newTarget = map[target];
this.newDelta = newTarget - newPos;
}
}
/**
* Constructor
*/
InjectBytecodes(ClassReaderWriter c, int length,
String className, String methodName) {
this.c = c;
this.output = System.out;
this.length = length;
this.map = new int[length + 1];
this.widening = new byte[length + 1];
this.className = className;
this.methodName = methodName;
c.markLocalPositionStart();
for (int i = 0; i <= length; ++i) {
map[i] = i;
}
}
public void inject(int at, byte[] newCode) {
snippets.put(new Integer(at), newCode);
trace("external ");
inject(at, newCode.length);
}
private void inject(int at, int len) {
if (Inject.verbose) {
traceln("Injecting " + len + " at " + at);
}
for (int i = at; i <= length; ++i) {
map[i] += len;
}
}
private void widen(int at, int len) {
int delta = len - widening[at];
if (Inject.verbose) {
traceln();
traceln("Widening to " + len + " at " + at);
}
inject(c.localPosition(), delta); // inject at end of instruction
widening[at] = (byte)len; // mark at beginning of instruction
}
public void injectBefore(int code, Injector inj) {
before[code] = inj;
}
public void injectAfter(int code, Injector inj) {
after[code] = inj;
}
private void trace(String str) {
if (Inject.verbose) {
output.print(str);
}
}
private void traceln(String str) {
if (Inject.verbose) {
output.println(str);
}
}
private void traceln() {
if (Inject.verbose) {
output.println();
}
}
private void trace(int i) {
if (Inject.verbose) {
output.print(i);
}
}
/**
* Print an integer so that it takes 'length' characters in
* the output. Temporary until formatting code is stable.
*/
private void traceFixedWidthInt(int x, int length) {
if (Inject.verbose) {
CharArrayWriter baStream = new CharArrayWriter();
PrintWriter pStream = new PrintWriter(baStream);
pStream.print(x);
String str = baStream.toString();
for (int cnt = length - str.length(); cnt > 0; --cnt)
trace(" ");
trace(str);
}
}
void adjustOffsets() throws IOException {
if (Inject.verbose) {
traceln();
traceln("Method " + methodName);
traceln();
}
c.rewind();
while (c.localPosition() < length) {
insertAtInstruction();
}
trace("Searching for adjustments...");
c.rewind();
while (c.localPosition() < length) {
if (!adjustInstruction()) {
c.rewind();
traceln();
traceln("Restarting adjustments after change...");
}
}
// write the new bytecodes
traceln();
traceln();
trace("Writing new code...");
c.rewind();
while (c.localPosition() < length) {
writeInstruction();
}
if (!snippets.isEmpty()) {
throw new Error("not all snippets written");
}
}
/**
* Walk one instruction inserting instrumentation at specified instructions
*/
private void insertAtInstruction() throws IOException {
pos = c.localPosition();
int opcode = c.readU1();
if (opcode == opc_wide) {
// no support for instrumenting wide instructions
int wopcode = c.readU1();
int lvIndex = c.readU2();
switch (wopcode) {
case opc_aload: case opc_astore:
case opc_fload: case opc_fstore:
case opc_iload: case opc_istore:
case opc_lload: case opc_lstore:
case opc_dload: case opc_dstore:
case opc_ret:
break;
case opc_iinc:
c.readS2();
break;
default:
throw new Error("Invalid wide opcode: " + wopcode);
}
} else {
Injector inj;
inj = before[opcode];
if (inj != null) {
inject(pos, inj.bytecodes(className, methodName, pos));
}
switch (opcode) {
case opc_tableswitch:{
int header = (pos+1+3) & (~3); // 4byte boundry
c.skip(header - (pos+1)); // skip old padding
c.readU4();
int low = c.readU4();
int high = c.readU4();
c.skip((high+1-low) * 4);
break;
}
case opc_lookupswitch:{
int header = (pos+1+3) & (~3); // 4byte boundry
c.skip(header - (pos+1)); // skip padding
c.readU4();
int npairs = c.readU4();
c.skip(npairs * 8);
break;
}
default: {
int instrLen = opcLengths[opcode];
c.skip(instrLen-1);
}
}
inj = after[opcode];
if (inj != null) {
pos = c.localPosition();
inject(pos, inj.bytecodes(className, methodName, pos));
}
}
}
/**
* Walk one instruction adjusting for insertions
*/
private boolean adjustInstruction() throws IOException {
pos = c.localPosition();
newPos = map[pos];
int opcode = c.readU1();
if (Inject.verbose) {
traceln();
traceFixedWidthInt(pos, 4);
traceFixedWidthInt(newPos, 4);
trace(" ");
}
if (opcode == opc_wide) {
int wopcode = c.readU1();
int lvIndex = c.readU2();
if (Inject.verbose) {
trace(opcNames[wopcode] + "_w ");
}
switch (wopcode) {
case opc_aload: case opc_astore:
case opc_fload: case opc_fstore:
case opc_iload: case opc_istore:
case opc_lload: case opc_lstore:
case opc_dload: case opc_dstore:
case opc_ret:
trace(lvIndex);
break;
case opc_iinc:
int constVal = c.readS2();
if (Inject.verbose) {
trace(lvIndex + " " + constVal);
}
break;
default:
throw new Error("Invalid wide opcode: " + wopcode);
}
} else {
if (Inject.verbose) {
trace(opcNames[opcode]);
}
switch (opcode) {
case opc_tableswitch:{
int widened = widening[pos];
int header = (pos+1+3) & (~3); // 4byte boundry
int newHeader = (newPos+1+3) & (~3); // 4byte boundry
c.skip(header - (pos+1)); // skip old padding
Span defaultSkip = new Span(c.readU4());
int low = c.readU4();
int high = c.readU4();
if (Inject.verbose) {
trace(" " + low + " to " + high);
trace(": default= [was] " + defaultSkip.target);
trace(" [now] " + defaultSkip.newTarget);
for (int i = low; i <= high; ++i) {
Span jump = new Span(c.readU4());
traceln("");
trace('\t');
traceFixedWidthInt(i, 5);
trace(": " + jump.newTarget);
}
} else {
c.skip((high+1-low) * 4);
}
int newPadding = newHeader - newPos;
int oldPadding = header - pos;
int deltaPadding = newPadding - oldPadding;
if (widened != deltaPadding) {
widen(pos, deltaPadding);
return false; // cause restart
}
break;
}
case opc_lookupswitch:{
int widened = widening[pos];
int header = (pos+1+3) & (~3); // 4byte boundry
int newHeader = (newPos+1+3) & (~3); // 4byte boundry
c.skip(header - (pos+1)); // skip old padding
Span defaultSkip = new Span(c.readU4());
int npairs = c.readU4();
if (Inject.verbose) {
trace(" npairs: " + npairs);
trace(": default= [was] " + defaultSkip.target);
trace(" [now] " + defaultSkip.newTarget);
for (int i = 0; i< npairs; ++i) {
int match = c.readU4();
Span jump = new Span(c.readU4());
traceln("");
trace('\t');
traceFixedWidthInt(match, 5);
trace(": " + jump.newTarget);
}
} else {
c.skip(npairs * 8);
}
int newPadding = newHeader - newPos;
int oldPadding = header - pos;
int deltaPadding = newPadding - oldPadding;
if (widened != deltaPadding) {
widen(pos, deltaPadding);
return false; // cause restart
}
break;
}
case opc_jsr: case opc_goto:
case opc_ifeq: case opc_ifge: case opc_ifgt:
case opc_ifle: case opc_iflt: case opc_ifne:
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull: {
int widened = widening[pos];
Span jump = new Span(c.readS2());
if (widened == 0) { // not yet widened
int newDelta = jump.newDelta;
if ((newDelta < -32768) || (newDelta > 32767)) {
switch (opcode) {
case opc_jsr: case opc_goto:
widen(pos, 2); // will convert to wide
break;
default:
widen(pos, 5); // will inject goto_w
break;
}
return false; // cause restart
}
}
if (Inject.verbose) {
trace(" [was] " + jump.target + " ==> " +
" [now] " + jump.newTarget);
}
break;
}
case opc_jsr_w:
case opc_goto_w: {
Span jump = new Span(c.readU4());
if (Inject.verbose) {
trace(" [was] " + jump.target +
" [now] " + jump.newTarget);
}
break;
}
default: {
int instrLen = opcLengths[opcode];
c.skip(instrLen-1);
break;
}
}
}
return true; // successful return
}
/**
* Walk one instruction writing the transformed instruction.
*/
private void writeInstruction() throws IOException {
pos = c.localPosition();
newPos = map[pos];
byte[] newCode = snippets.remove(new Integer(pos));
if (newCode != null) {
traceln();
traceFixedWidthInt(pos, 4);
trace(" ... -- Inserting new code");
c.writeBytes(newCode);
}
int opcode = c.readU1();
if (Inject.verbose) {
traceln();
traceFixedWidthInt(pos, 4);
traceFixedWidthInt(newPos, 4);
trace(" ");
}
if (opcode == opc_wide) {
int wopcode = c.readU1();
int lvIndex = c.readU2();
if (Inject.verbose) {
trace(opcNames[wopcode] + "_w ");
}
c.writeU1(opcode);
c.writeU1(wopcode);
c.writeU2(lvIndex);
switch (wopcode) {
case opc_aload: case opc_astore:
case opc_fload: case opc_fstore:
case opc_iload: case opc_istore:
case opc_lload: case opc_lstore:
case opc_dload: case opc_dstore:
case opc_ret:
trace(lvIndex);
break;
case opc_iinc:
int constVal = c.readS2();
c.writeU2(constVal); // ??? U vs S
if (Inject.verbose) {
trace(lvIndex + " " + constVal);
}
break;
default:
throw new Error("Invalid wide opcode: " + wopcode);
}
} else {
if (Inject.verbose) {
trace(opcNames[opcode]);
}
switch (opcode) {
case opc_tableswitch:{
int header = (pos+1+3) & (~3); // 4byte boundry
int newHeader = (newPos+1+3) & (~3); // 4byte boundry
c.skip(header - (pos+1)); // skip old padding
Span defaultSkip = new Span(c.readU4());
int low = c.readU4();
int high = c.readU4();
c.writeU1(opcode); // copy instruction
for (int i = newPos+1; i < newHeader; ++i) {
c.writeU1(0); // write new padding
}
c.writeU4(defaultSkip.newDelta);
c.writeU4(low);
c.writeU4(high);
if (Inject.verbose) {
trace(" " + low + " to " + high);
trace(": default= [was] " + defaultSkip.target);
trace(" [now] " + defaultSkip.newTarget);
}
for (int i = low; i <= high; ++i) {
Span jump = new Span(c.readU4());
c.writeU4(jump.newDelta);
if (Inject.verbose) {
traceln("");
trace('\t');
traceFixedWidthInt(i, 5);
trace(": " + jump.newTarget);
}
}
break;
}
case opc_lookupswitch:{
int header = (pos+1+3) & (~3); // 4byte boundry
int newHeader = (newPos+1+3) & (~3); // 4byte boundry
c.skip(header - (pos+1)); // skip old padding
Span defaultSkip = new Span(c.readU4());
int npairs = c.readU4();
if (Inject.verbose) {
trace(" npairs: " + npairs);
trace(": default= [was] " + defaultSkip.target);
trace(" [now] " + defaultSkip.newTarget);
}
c.writeU1(opcode); // copy instruction
for (int i = newPos+1; i < newHeader; ++i) {
c.writeU1(0); // write new padding
}
c.writeU4(defaultSkip.newDelta);
c.writeU4(npairs);
for (int i = 0; i< npairs; ++i) {
int match = c.readU4();
Span jump = new Span(c.readU4());
c.writeU4(match);
c.writeU4(jump.newDelta);
if (Inject.verbose) {
traceln("");
trace('\t');
traceFixedWidthInt(match, 5);
trace(": " + jump.newTarget);
}
}
break;
}
case opc_jsr: case opc_goto:
case opc_ifeq: case opc_ifge: case opc_ifgt:
case opc_ifle: case opc_iflt: case opc_ifne:
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull: {
int widened = widening[pos];
Span jump = new Span(c.readS2());
int newOpcode = opcode; // default to unchanged
if (widened == 0) { // not widened
c.writeU1(opcode); // rewrite instruction
c.writeU2(jump.newDelta);
} else if (widened == 2) { // wide form
switch (opcode) {
case opc_jsr:
newOpcode = opc_jsr_w;
break;
case opc_goto:
newOpcode = opc_jsr_w;
break;
default:
throw new Error("unexpected opcode: " +
opcode);
}
c.writeU1(newOpcode); // write wide instruction
c.writeU4(jump.newDelta); // write new and wide delta
} else if (widened == 5) { // insert goto_w
switch (opcode) {
case opc_ifeq:
newOpcode = opc_ifne;
break;
case opc_ifge:
newOpcode = opc_iflt;
break;
case opc_ifgt:
newOpcode = opc_ifle;
break;
case opc_ifle:
newOpcode = opc_ifgt;
break;
case opc_iflt:
newOpcode = opc_ifge;
break;
case opc_ifne:
newOpcode = opc_ifeq;
break;
case opc_if_icmpeq:
newOpcode = opc_if_icmpne;
break;
case opc_if_icmpne:
newOpcode = opc_if_icmpeq;
break;
case opc_if_icmpge:
newOpcode = opc_if_icmplt;
break;
case opc_if_icmpgt:
newOpcode = opc_if_icmple;
break;
case opc_if_icmple:
newOpcode = opc_if_icmpgt;
break;
case opc_if_icmplt:
newOpcode = opc_if_icmpge;
break;
case opc_if_acmpeq:
newOpcode = opc_if_acmpne;
break;
case opc_if_acmpne:
newOpcode = opc_if_acmpeq;
break;
case opc_ifnull:
newOpcode = opc_ifnonnull;
break;
case opc_ifnonnull:
newOpcode = opc_ifnull;
break;
default:
throw new Error("unexpected opcode: " +
opcode);
}
c.writeU1(newOpcode); // write inverse branch
c.writeU2(3 + 5); // beyond if and goto_w
c.writeU1(opc_goto_w);// add a goto_w
c.writeU4(jump.newDelta); // write new and wide delta
} else {
throw new Error("unexpected widening");
}
if (Inject.verbose) {
trace(" [was] " + jump.target + " ==> " +
opcNames[newOpcode] +
" [now] " + jump.newTarget);
}
break;
}
case opc_jsr_w:
case opc_goto_w: {
Span jump = new Span(c.readU4());
c.writeU1(opcode); // instruction itself
c.writeU4(jump.newDelta);
if (Inject.verbose) {
trace(" [was] " + jump.target +
" [now] " + jump.newTarget);
}
break;
}
default: {
int instrLen = opcLengths[opcode];
c.writeU1(opcode); // instruction itself
c.copy(instrLen-1);
}
}
}
}
/**
* Copy the exception table for this method code
*/
void copyExceptionTable() throws IOException {
int tableLength = c.copyU2(); // exception table len
if (tableLength > 0) {
traceln();
traceln("Exception table:");
traceln(" from:old/new to:old/new target:old/new type");
for (int tcnt = tableLength; tcnt > 0; --tcnt) {
int startPC = c.readU2();
int newStartPC = map[startPC];
c.writeU2(newStartPC);
int endPC = c.readU2();
int newEndPC = map[endPC];
c.writeU2(newEndPC);
int handlerPC = c.readU2();
int newHandlerPC = map[handlerPC];
c.writeU2(newHandlerPC);
int catchType = c.copyU2();
if (Inject.verbose) {
traceFixedWidthInt(startPC, 6);
traceFixedWidthInt(newStartPC, 6);
traceFixedWidthInt(endPC, 6);
traceFixedWidthInt(newEndPC, 6);
traceFixedWidthInt(handlerPC, 6);
traceFixedWidthInt(newHandlerPC, 6);
trace(" ");
if (catchType == 0)
traceln("any");
else {
traceln("" + catchType);
}
}
}
}
}
/**
* Copy the line number table for this method code
*/
void copyLineNumberAttr() throws IOException {
// name index already read
c.copy(4); // attr len
int tableLength = c.copyU2(); // line table len
if (tableLength > 0) {
if (Inject.verbose) {
traceln();
traceln("Line numbers for method " + methodName);
}
for (int tcnt = tableLength; tcnt > 0; --tcnt) {
int startPC = c.readU2();
int newStartPC = map[startPC];
c.writeU2(newStartPC);
int lineNumber = c.copyU2();
if (Inject.verbose) {
traceln(" line " + lineNumber +
": [was] " + startPC +
" [now] " + newStartPC);
}
}
}
}
/**
* Copy the local variable table for this method code
*/
void copyLocalVarAttr() throws IOException {
// name index already read
c.copy(4); // attr len
int tableLength = c.copyU2(); // local var table len
if (tableLength > 0) {
if (Inject.verbose) {
traceln();
traceln("Local variables for method " + methodName);
}
for (int tcnt = tableLength; tcnt > 0; --tcnt) {
int startPC = c.readU2();
int newStartPC = map[startPC];
c.writeU2(newStartPC);
int length = c.readU2();
int endPC = startPC + length;
int newEndPC = map[endPC];
int newLength = newEndPC - newStartPC;
c.writeU2(newLength);
int nameIndex = c.copyU2();
int descriptorIndex = c.copyU2();
int index = c.copyU2();
if (Inject.verbose) {
trace(" ");
trace(descriptorIndex);
trace(" ");
trace(nameIndex);
traceln(" pc= [was] " + startPC + " [now] " + newStartPC +
", length= [was] " + length + " [now] " + newLength +
", slot=" + index);
}
}
}
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package ilib;
interface Injector {
byte[] bytecodes(String className, String methodName, int location);
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package ilib;
public class Options {
public boolean shouldInstrumentNew = false;
public boolean shouldInstrumentCall = false;
public boolean shouldInstrumentIndexed = false;
public boolean shouldInstrumentObject = false;
public boolean shouldInstrumentObjectInit = false;
public boolean shouldInstrumentNativeMethods = false;
public String targetMethod = null;
public int fixedIndex = 0;
public String trackerClassName = "MyTracker";
public String allocTrackerMethodName = "allocTracker";
public String callTrackerMethodName = "callTracker";
public String wrappedTrackerMethodName = "wrappedTracker";
public String wrappedPrefix = "wrapped_up_";
}

View File

@ -1,732 +0,0 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package ilib;
public interface RuntimeConstants {
/* Signature Characters */
char SIGC_VOID = 'V';
String SIG_VOID = "V";
char SIGC_BOOLEAN = 'Z';
String SIG_BOOLEAN = "Z";
char SIGC_BYTE = 'B';
String SIG_BYTE = "B";
char SIGC_CHAR = 'C';
String SIG_CHAR = "C";
char SIGC_SHORT = 'S';
String SIG_SHORT = "S";
char SIGC_INT = 'I';
String SIG_INT = "I";
char SIGC_LONG = 'J';
String SIG_LONG = "J";
char SIGC_FLOAT = 'F';
String SIG_FLOAT = "F";
char SIGC_DOUBLE = 'D';
String SIG_DOUBLE = "D";
char SIGC_ARRAY = '[';
String SIG_ARRAY = "[";
char SIGC_CLASS = 'L';
String SIG_CLASS = "L";
char SIGC_METHOD = '(';
String SIG_METHOD = "(";
char SIGC_ENDCLASS = ';';
String SIG_ENDCLASS = ";";
char SIGC_ENDMETHOD = ')';
String SIG_ENDMETHOD = ")";
char SIGC_PACKAGE = '/';
String SIG_PACKAGE = "/";
/* Class File Constants */
int JAVA_MAGIC = 0xcafebabe;
int JAVA_MIN_SUPPORTED_VERSION = 45;
int JAVA_MAX_SUPPORTED_VERSION = 48;
int JAVA_MAX_SUPPORTED_MINOR_VERSION = 0;
/* Generate class file version for 1.1 by default */
int JAVA_DEFAULT_VERSION = 45;
int JAVA_DEFAULT_MINOR_VERSION = 3;
/* Constant table */
int CONSTANT_UTF8 = 1;
int CONSTANT_UNICODE = 2;
int CONSTANT_INTEGER = 3;
int CONSTANT_FLOAT = 4;
int CONSTANT_LONG = 5;
int CONSTANT_DOUBLE = 6;
int CONSTANT_CLASS = 7;
int CONSTANT_STRING = 8;
int CONSTANT_FIELD = 9;
int CONSTANT_METHOD = 10;
int CONSTANT_INTERFACEMETHOD = 11;
int CONSTANT_NAMEANDTYPE = 12;
/* Access and modifier flags */
int ACC_PUBLIC = 0x00000001;
int ACC_PRIVATE = 0x00000002;
int ACC_PROTECTED = 0x00000004;
int ACC_STATIC = 0x00000008;
int ACC_FINAL = 0x00000010;
int ACC_SYNCHRONIZED = 0x00000020;
int ACC_VOLATILE = 0x00000040;
int ACC_TRANSIENT = 0x00000080;
int ACC_NATIVE = 0x00000100;
int ACC_INTERFACE = 0x00000200;
int ACC_ABSTRACT = 0x00000400;
int ACC_SUPER = 0x00000020;
int ACC_STRICT = 0x00000800;
/* Type codes */
int T_CLASS = 0x00000002;
int T_BOOLEAN = 0x00000004;
int T_CHAR = 0x00000005;
int T_FLOAT = 0x00000006;
int T_DOUBLE = 0x00000007;
int T_BYTE = 0x00000008;
int T_SHORT = 0x00000009;
int T_INT = 0x0000000a;
int T_LONG = 0x0000000b;
/* Opcodes */
int opc_try = -3;
int opc_dead = -2;
int opc_label = -1;
int opc_nop = 0;
int opc_aconst_null = 1;
int opc_iconst_m1 = 2;
int opc_iconst_0 = 3;
int opc_iconst_1 = 4;
int opc_iconst_2 = 5;
int opc_iconst_3 = 6;
int opc_iconst_4 = 7;
int opc_iconst_5 = 8;
int opc_lconst_0 = 9;
int opc_lconst_1 = 10;
int opc_fconst_0 = 11;
int opc_fconst_1 = 12;
int opc_fconst_2 = 13;
int opc_dconst_0 = 14;
int opc_dconst_1 = 15;
int opc_bipush = 16;
int opc_sipush = 17;
int opc_ldc = 18;
int opc_ldc_w = 19;
int opc_ldc2_w = 20;
int opc_iload = 21;
int opc_lload = 22;
int opc_fload = 23;
int opc_dload = 24;
int opc_aload = 25;
int opc_iload_0 = 26;
int opc_iload_1 = 27;
int opc_iload_2 = 28;
int opc_iload_3 = 29;
int opc_lload_0 = 30;
int opc_lload_1 = 31;
int opc_lload_2 = 32;
int opc_lload_3 = 33;
int opc_fload_0 = 34;
int opc_fload_1 = 35;
int opc_fload_2 = 36;
int opc_fload_3 = 37;
int opc_dload_0 = 38;
int opc_dload_1 = 39;
int opc_dload_2 = 40;
int opc_dload_3 = 41;
int opc_aload_0 = 42;
int opc_aload_1 = 43;
int opc_aload_2 = 44;
int opc_aload_3 = 45;
int opc_iaload = 46;
int opc_laload = 47;
int opc_faload = 48;
int opc_daload = 49;
int opc_aaload = 50;
int opc_baload = 51;
int opc_caload = 52;
int opc_saload = 53;
int opc_istore = 54;
int opc_lstore = 55;
int opc_fstore = 56;
int opc_dstore = 57;
int opc_astore = 58;
int opc_istore_0 = 59;
int opc_istore_1 = 60;
int opc_istore_2 = 61;
int opc_istore_3 = 62;
int opc_lstore_0 = 63;
int opc_lstore_1 = 64;
int opc_lstore_2 = 65;
int opc_lstore_3 = 66;
int opc_fstore_0 = 67;
int opc_fstore_1 = 68;
int opc_fstore_2 = 69;
int opc_fstore_3 = 70;
int opc_dstore_0 = 71;
int opc_dstore_1 = 72;
int opc_dstore_2 = 73;
int opc_dstore_3 = 74;
int opc_astore_0 = 75;
int opc_astore_1 = 76;
int opc_astore_2 = 77;
int opc_astore_3 = 78;
int opc_iastore = 79;
int opc_lastore = 80;
int opc_fastore = 81;
int opc_dastore = 82;
int opc_aastore = 83;
int opc_bastore = 84;
int opc_castore = 85;
int opc_sastore = 86;
int opc_pop = 87;
int opc_pop2 = 88;
int opc_dup = 89;
int opc_dup_x1 = 90;
int opc_dup_x2 = 91;
int opc_dup2 = 92;
int opc_dup2_x1 = 93;
int opc_dup2_x2 = 94;
int opc_swap = 95;
int opc_iadd = 96;
int opc_ladd = 97;
int opc_fadd = 98;
int opc_dadd = 99;
int opc_isub = 100;
int opc_lsub = 101;
int opc_fsub = 102;
int opc_dsub = 103;
int opc_imul = 104;
int opc_lmul = 105;
int opc_fmul = 106;
int opc_dmul = 107;
int opc_idiv = 108;
int opc_ldiv = 109;
int opc_fdiv = 110;
int opc_ddiv = 111;
int opc_irem = 112;
int opc_lrem = 113;
int opc_frem = 114;
int opc_drem = 115;
int opc_ineg = 116;
int opc_lneg = 117;
int opc_fneg = 118;
int opc_dneg = 119;
int opc_ishl = 120;
int opc_lshl = 121;
int opc_ishr = 122;
int opc_lshr = 123;
int opc_iushr = 124;
int opc_lushr = 125;
int opc_iand = 126;
int opc_land = 127;
int opc_ior = 128;
int opc_lor = 129;
int opc_ixor = 130;
int opc_lxor = 131;
int opc_iinc = 132;
int opc_i2l = 133;
int opc_i2f = 134;
int opc_i2d = 135;
int opc_l2i = 136;
int opc_l2f = 137;
int opc_l2d = 138;
int opc_f2i = 139;
int opc_f2l = 140;
int opc_f2d = 141;
int opc_d2i = 142;
int opc_d2l = 143;
int opc_d2f = 144;
int opc_i2b = 145;
int opc_i2c = 146;
int opc_i2s = 147;
int opc_lcmp = 148;
int opc_fcmpl = 149;
int opc_fcmpg = 150;
int opc_dcmpl = 151;
int opc_dcmpg = 152;
int opc_ifeq = 153;
int opc_ifne = 154;
int opc_iflt = 155;
int opc_ifge = 156;
int opc_ifgt = 157;
int opc_ifle = 158;
int opc_if_icmpeq = 159;
int opc_if_icmpne = 160;
int opc_if_icmplt = 161;
int opc_if_icmpge = 162;
int opc_if_icmpgt = 163;
int opc_if_icmple = 164;
int opc_if_acmpeq = 165;
int opc_if_acmpne = 166;
int opc_goto = 167;
int opc_jsr = 168;
int opc_ret = 169;
int opc_tableswitch = 170;
int opc_lookupswitch = 171;
int opc_ireturn = 172;
int opc_lreturn = 173;
int opc_freturn = 174;
int opc_dreturn = 175;
int opc_areturn = 176;
int opc_return = 177;
int opc_getstatic = 178;
int opc_putstatic = 179;
int opc_getfield = 180;
int opc_putfield = 181;
int opc_invokevirtual = 182;
int opc_invokespecial = 183;
int opc_invokestatic = 184;
int opc_invokeinterface = 185;
int opc_xxxunusedxxx = 186;
int opc_new = 187;
int opc_newarray = 188;
int opc_anewarray = 189;
int opc_arraylength = 190;
int opc_athrow = 191;
int opc_checkcast = 192;
int opc_instanceof = 193;
int opc_monitorenter = 194;
int opc_monitorexit = 195;
int opc_wide = 196;
int opc_multianewarray = 197;
int opc_ifnull = 198;
int opc_ifnonnull = 199;
int opc_goto_w = 200;
int opc_jsr_w = 201;
int opc_breakpoint = 202;
/* Opcode Names */
String opcNames[] = {
"nop",
"aconst_null",
"iconst_m1",
"iconst_0",
"iconst_1",
"iconst_2",
"iconst_3",
"iconst_4",
"iconst_5",
"lconst_0",
"lconst_1",
"fconst_0",
"fconst_1",
"fconst_2",
"dconst_0",
"dconst_1",
"bipush",
"sipush",
"ldc",
"ldc_w",
"ldc2_w",
"iload",
"lload",
"fload",
"dload",
"aload",
"iload_0",
"iload_1",
"iload_2",
"iload_3",
"lload_0",
"lload_1",
"lload_2",
"lload_3",
"fload_0",
"fload_1",
"fload_2",
"fload_3",
"dload_0",
"dload_1",
"dload_2",
"dload_3",
"aload_0",
"aload_1",
"aload_2",
"aload_3",
"iaload",
"laload",
"faload",
"daload",
"aaload",
"baload",
"caload",
"saload",
"istore",
"lstore",
"fstore",
"dstore",
"astore",
"istore_0",
"istore_1",
"istore_2",
"istore_3",
"lstore_0",
"lstore_1",
"lstore_2",
"lstore_3",
"fstore_0",
"fstore_1",
"fstore_2",
"fstore_3",
"dstore_0",
"dstore_1",
"dstore_2",
"dstore_3",
"astore_0",
"astore_1",
"astore_2",
"astore_3",
"iastore",
"lastore",
"fastore",
"dastore",
"aastore",
"bastore",
"castore",
"sastore",
"pop",
"pop2",
"dup",
"dup_x1",
"dup_x2",
"dup2",
"dup2_x1",
"dup2_x2",
"swap",
"iadd",
"ladd",
"fadd",
"dadd",
"isub",
"lsub",
"fsub",
"dsub",
"imul",
"lmul",
"fmul",
"dmul",
"idiv",
"ldiv",
"fdiv",
"ddiv",
"irem",
"lrem",
"frem",
"drem",
"ineg",
"lneg",
"fneg",
"dneg",
"ishl",
"lshl",
"ishr",
"lshr",
"iushr",
"lushr",
"iand",
"land",
"ior",
"lor",
"ixor",
"lxor",
"iinc",
"i2l",
"i2f",
"i2d",
"l2i",
"l2f",
"l2d",
"f2i",
"f2l",
"f2d",
"d2i",
"d2l",
"d2f",
"i2b",
"i2c",
"i2s",
"lcmp",
"fcmpl",
"fcmpg",
"dcmpl",
"dcmpg",
"ifeq",
"ifne",
"iflt",
"ifge",
"ifgt",
"ifle",
"if_icmpeq",
"if_icmpne",
"if_icmplt",
"if_icmpge",
"if_icmpgt",
"if_icmple",
"if_acmpeq",
"if_acmpne",
"goto",
"jsr",
"ret",
"tableswitch",
"lookupswitch",
"ireturn",
"lreturn",
"freturn",
"dreturn",
"areturn",
"return",
"getstatic",
"putstatic",
"getfield",
"putfield",
"invokevirtual",
"invokespecial",
"invokestatic",
"invokeinterface",
"xxxunusedxxx",
"new",
"newarray",
"anewarray",
"arraylength",
"athrow",
"checkcast",
"instanceof",
"monitorenter",
"monitorexit",
"wide",
"multianewarray",
"ifnull",
"ifnonnull",
"goto_w",
"jsr_w",
"breakpoint"
};
/* Opcode Lengths */
int opcLengths[] = {
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
3,
2,
3,
3,
2,
2,
2,
2,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
3,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
2,
99,
99,
1,
1,
1,
1,
1,
1,
3,
3,
3,
3,
3,
3,
3,
5,
0,
3,
2,
3,
1,
1,
3,
3,
1,
1,
0,
4,
3,
3,
5,
5,
1
};
}