/** Returns the constant string at the specified offset */ public static String get_constant_str(ConstantPool pool, int index) { Constant c = pool.getConstant(index); if (c instanceof ConstantUtf8) return ((ConstantUtf8) c).getBytes(); else if (c instanceof ConstantClass) { ConstantClass cc = (ConstantClass) c; return cc.getBytes(pool) + " [" + cc.getNameIndex() + "]"; } else assert false : "unexpected constant " + c + " class " + c.getClass(); return (null); }
/** @param cp */ public void resolveCPool(ConstantPool cp) { Constant[] ca = cp.getConstantPool(); cpoolArry = new int[cpoolUsed.size()]; cpoolComments = new String[ca.length]; // System.out.println(clazz.getClassName()+" cpool "+cpoolUsed); for (int i = 0; i < ca.length; ++i) { Constant co = ca[i]; Integer idx = new Integer(i); // pos is the new position in the reduced constant pool // idx is the position in the 'original' unresolved cpool int pos = cpoolUsed.indexOf(idx); if (pos != -1) { boolean isInterface = false; // System.out.println("cpool@"+pos+" = orig_cp@"+i+" "+co); switch (co.getTag()) { case Constants.CONSTANT_Integer: cpoolArry[pos] = ((ConstantInteger) co).getBytes(); cpoolComments[pos] = "Integer"; break; case Constants.CONSTANT_Long: long lval = ((ConstantLong) co).getBytes(); // store LOW, HIGH words in this order int loW = (new Long(0xFFFFFFFF & lval)).intValue(); int hiW = (new Long(lval >>> 32)).intValue(); cpoolArry[pos] = hiW; cpoolArry[pos + 1] = loW; cpoolComments[pos] = "Long: " + lval; cpoolComments[pos + 1] = ""; break; case Constants.CONSTANT_Float: float fval = ((ConstantFloat) co).getBytes(); cpoolArry[pos] = Float.floatToRawIntBits(fval); cpoolComments[pos] = "Float: " + fval; break; case Constants.CONSTANT_Double: double dval = ((ConstantDouble) co).getBytes(); long d_lval = Double.doubleToRawLongBits(dval); // store LOW, HIGH words in this order int d_loW = (new Long(0xFFFFFFFF & d_lval)).intValue(); int d_hiW = (new Long(d_lval >>> 32)).intValue(); cpoolArry[pos] = d_hiW; cpoolArry[pos + 1] = d_loW; cpoolComments[pos] = "Double: " + dval; cpoolComments[pos + 1] = ""; break; case Constants.CONSTANT_String: String str = ((ConstantString) co).getBytes(cp); StringInfo si = StringInfo.getStringInfo(str); cpoolArry[pos] = StringInfo.stringTableAddress + si.getAddress(); cpoolComments[pos] = "String: " + si.getSaveString(); break; case Constants.CONSTANT_Class: String clname = ((ConstantClass) co).getBytes(cp).replace('/', '.'); JopClassInfo clinfo = (JopClassInfo) appInfo.cliMap.get(clname); if (clinfo == null) { cpoolComments[pos] = "Problem with class: " + clname; String type = clname.substring(clname.length() - 2); if (type.charAt(0) == '[') { switch (type.charAt(1)) { case 'Z': cpoolArry[pos] = 4; break; case 'C': cpoolArry[pos] = 5; break; case 'F': cpoolArry[pos] = 6; break; case 'D': cpoolArry[pos] = 7; break; case 'B': cpoolArry[pos] = 8; break; case 'S': cpoolArry[pos] = 9; break; case 'I': cpoolArry[pos] = 10; break; case 'J': cpoolArry[pos] = 11; break; default:; // all other types are missing... } } // System.out.println(cpoolComments[pos]+" "+type+" "+cpoolArry[pos]); continue; } cpoolArry[pos] = clinfo.classRefAddress; cpoolComments[pos] = "Class: " + clname; break; case Constants.CONSTANT_InterfaceMethodref: isInterface = true; case Constants.CONSTANT_Methodref: // find the class for this method int mclidx; if (isInterface) { mclidx = ((ConstantInterfaceMethodref) co).getClassIndex(); } else { mclidx = ((ConstantMethodref) co).getClassIndex(); } ConstantClass mcl = (ConstantClass) cp.getConstant(mclidx); // the method has "/" instead of ".", fix that // now get the signature too... String mclname = mcl.getBytes(cp).replace('/', '.'); int sigidx; if (isInterface) { sigidx = ((ConstantInterfaceMethodref) co).getNameAndTypeIndex(); } else { sigidx = ((ConstantMethodref) co).getNameAndTypeIndex(); } ConstantNameAndType signt = (ConstantNameAndType) cp.getConstant(sigidx); String sigstr = signt.getName(cp) + signt.getSignature(cp); // now find the address of the method struct! JopClassInfo clinf = (JopClassInfo) appInfo.cliMap.get(mclname); if (clinf == null) { // probably a reference to Native - a class that // is NOT present in the application. // we could avoid this by not adding method refs to // Native in our reduced cpool. cpoolArry[pos] = 0; cpoolComments[pos] = "static " + mclname + "." + sigstr; break; } JopMethodInfo minf; if (isInterface) { minf = clinf.getITMethodInfo(sigstr); } else { minf = clinf.getVTMethodInfo(sigstr); } if (minf == null) { System.out.println( "Error: Method " + clinf.clazz.getClassName() + '.' + sigstr + " not found."); System.out.println("Invoked by " + clazz.getClassName()); for (int xxx = 0; xxx < clinf.clvt.len; ++xxx) { System.out.println(clinf.clvt.key[xxx]); } System.exit(1); } if (minf.getMethod().isStatic() || // <init> and privat methods are called with invokespecial // which mapps in jvm.asm to invokestatic minf.getMethod().isPrivate() || sigstr.charAt(0) == '<') { // for static methods a direct pointer to the // method struct cpoolArry[pos] = minf.structAddress; cpoolComments[pos] = "static, special or private " + clinf.clazz.getClassName() + "." + minf.methodId; } else { // as Flavius correctly comments: // TODO: CHANGE THIS TO A MORE CONSISTENT FORMAT... // extract the objref! for some reason the microcode // needs -1 here...weird // that's for simple virtual methods int vpos = minf.vtindex; String comment = "virtual"; // TODO: is kind of redundant search as we've already // searched the IT table with getVTMethodInfo() // TODO: do we handle different interfaces with same // method id correct? (see buildIT) if (isInterface) { comment = "interface"; for (int j = 0; j < listIT.size(); ++j) { IT it = (IT) listIT.get(j); if (it.key.equals(minf.methodId)) { vpos = j; break; } } // offest in interface table // index plus number of arguments (without this!) cpoolArry[pos] = (vpos << 8) + (minf.margs - 1); } else { // offest in method table // (index*2) plus number of arguments (without // this!) cpoolArry[pos] = (vpos * ClassStructConstants.METH_STR << 8) + (minf.margs - 1); } cpoolComments[pos] = comment + " index: " + vpos + " args: " + minf.margs + " " + clinf.clazz.getClassName() + "." + minf.methodId; } break; case Constants.CONSTANT_Fieldref: throw new Error("Fieldref should not be used anymore"); // int fidx = ((ConstantFieldref) co).getClassIndex(); // ConstantClass fcl = (ConstantClass) cp.getConstant(fidx); // String fclname = fcl.getBytes(cp).replace('/', '.'); // // got the class name // sigidx = ((ConstantFieldref) co).getNameAndTypeIndex(); // signt = (ConstantNameAndType) cp.getConstant(sigidx); // sigstr = signt.getName(cp) + signt.getSignature(cp); // clinf = (JopClassInfo) appInfo.cliMap.get(fclname); // int j; // String comment = ""; // boolean found = false; // while (!found) { // for (j = 0; j < clinf.clft.len; ++j) { // if (clinf.clft.key[j].equals(sigstr)) { // found = true; // if (clinf.clft.isStatic[j]) { // comment = "static "; // } // // for static fields a direct pointer to the // // static field // cpoolArry[pos] = clinf.clft.idx[j]; // cpoolComments[pos] = comment // + clinf.clazz.getClassName() + "." // + sigstr; // break; // } // } // if (!found) { // clinf = (JopClassInfo) clinf.superClass; // if (clinf == null) { // System.out.println("Error: field " + fclname // + "." + sigstr + " not found!"); // break; // } // } // } // break; default: System.out.println("TODO: cpool@" + pos + " = orig_cp@" + i + " " + co); cpoolComments[pos] = "Problem with: " + co; } } } }
/** * Adds all the constants found in the given class into the given ConstantSet, and returns it. * * @see #getConstants(String) */ public static ConstantSet getConstants(String classname, ConstantSet result) { ClassParser cp; JavaClass jc; try { String classfileBase = classname.replace('.', '/'); InputStream is = ClassPath.SYSTEM_CLASS_PATH.getInputStream(classfileBase, ".class"); cp = new ClassParser(is, classname); jc = cp.parse(); } catch (java.io.IOException e) { throw new Error("IOException while reading '" + classname + "': " + e.getMessage()); } result.classname = jc.getClassName(); // Get all of the constants from the pool ConstantPool constant_pool = jc.getConstantPool(); for (Constant c : constant_pool.getConstantPool()) { // System.out.printf ("*Constant = %s%n", c); if (c == null || c instanceof ConstantClass || c instanceof ConstantFieldref || c instanceof ConstantInterfaceMethodref || c instanceof ConstantMethodref || c instanceof ConstantNameAndType || c instanceof ConstantUtf8) { continue; } if (c instanceof ConstantString) { result.strings.add((String) ((ConstantString) c).getConstantValue(constant_pool)); } else if (c instanceof ConstantDouble) { result.doubles.add((Double) ((ConstantDouble) c).getConstantValue(constant_pool)); } else if (c instanceof ConstantFloat) { result.floats.add((Float) ((ConstantFloat) c).getConstantValue(constant_pool)); } else if (c instanceof ConstantInteger) { result.ints.add((Integer) ((ConstantInteger) c).getConstantValue(constant_pool)); } else if (c instanceof ConstantLong) { result.longs.add((Long) ((ConstantLong) c).getConstantValue(constant_pool)); } else { throw new RuntimeException("Unrecognized constant of type " + c.getClass() + ": " + c); } } ClassGen gen = new ClassGen(jc); ConstantPoolGen pool = gen.getConstantPool(); // Process the code in each method looking for literals for (Method m : jc.getMethods()) { MethodGen mg = new MethodGen(m, jc.getClassName(), pool); InstructionList il = mg.getInstructionList(); if (il == null) { // System.out.println("No instructions for " + mg); } else { for (Instruction inst : il.getInstructions()) { switch (inst.getOpcode()) { // Compare two objects, no literals case Constants.IF_ACMPEQ: case Constants.IF_ACMPNE: break; // These instructions compare the integer on the top of the stack // to zero. There are no literals here (except 0) case Constants.IFEQ: case Constants.IFNE: case Constants.IFLT: case Constants.IFGE: case Constants.IFGT: case Constants.IFLE: { break; } // Instanceof pushes either 0 or 1 on the stack depending on whether // the object on top of stack is of the specified type. // If were interested in class literals, this would be interesting case Constants.INSTANCEOF: break; // Duplicates the item on the top of stack. No literal. case Constants.DUP: { break; } // Duplicates the item on the top of the stack and inserts it 2 // values down in the stack. No literals case Constants.DUP_X1: { break; } // Duplicates either the top 2 category 1 values or a single // category 2 value and inserts it 2 or 3 values down on the // stack. case Constants.DUP2_X1: { break; } // Duplicate either one category 2 value or two category 1 values. case Constants.DUP2: { break; } // Dup the category 1 value on the top of the stack and insert it either // two or three values down on the stack. case Constants.DUP_X2: { break; } case Constants.DUP2_X2: { break; } // Pop instructions discard the top of the stack. case Constants.POP: { break; } // Pops either the top 2 category 1 values or a single category 2 value // from the top of the stack. case Constants.POP2: { break; } // Swaps the two category 1 types on the top of the stack. case Constants.SWAP: { break; } // Compares two integers on the stack case Constants.IF_ICMPEQ: case Constants.IF_ICMPGE: case Constants.IF_ICMPGT: case Constants.IF_ICMPLE: case Constants.IF_ICMPLT: case Constants.IF_ICMPNE: { break; } // Get the value of a field case Constants.GETFIELD: { break; } // stores the top of stack into a field case Constants.PUTFIELD: { break; } // Pushes the value of a static field on the stack case Constants.GETSTATIC: { break; } // Pops a value off of the stack into a static field case Constants.PUTSTATIC: { break; } // pushes a local onto the stack case Constants.DLOAD: case Constants.DLOAD_0: case Constants.DLOAD_1: case Constants.DLOAD_2: case Constants.DLOAD_3: case Constants.FLOAD: case Constants.FLOAD_0: case Constants.FLOAD_1: case Constants.FLOAD_2: case Constants.FLOAD_3: case Constants.ILOAD: case Constants.ILOAD_0: case Constants.ILOAD_1: case Constants.ILOAD_2: case Constants.ILOAD_3: case Constants.LLOAD: case Constants.LLOAD_0: case Constants.LLOAD_1: case Constants.LLOAD_2: case Constants.LLOAD_3: { break; } // Pops a value off of the stack into a local case Constants.DSTORE: case Constants.DSTORE_0: case Constants.DSTORE_1: case Constants.DSTORE_2: case Constants.DSTORE_3: case Constants.FSTORE: case Constants.FSTORE_0: case Constants.FSTORE_1: case Constants.FSTORE_2: case Constants.FSTORE_3: case Constants.ISTORE: case Constants.ISTORE_0: case Constants.ISTORE_1: case Constants.ISTORE_2: case Constants.ISTORE_3: case Constants.LSTORE: case Constants.LSTORE_0: case Constants.LSTORE_1: case Constants.LSTORE_2: case Constants.LSTORE_3: { break; } // Push a value from the runtime constant pool. We'll get these // values when processing the constant pool itself case Constants.LDC: case Constants.LDC_W: case Constants.LDC2_W: { break; } // Push the length of an array on the stack case Constants.ARRAYLENGTH: { break; } // Push small constants (-1..5) on the stack. These literals are // too common to bother mentioning case Constants.DCONST_0: case Constants.DCONST_1: case Constants.FCONST_0: case Constants.FCONST_1: case Constants.FCONST_2: case Constants.ICONST_0: case Constants.ICONST_1: case Constants.ICONST_2: case Constants.ICONST_3: case Constants.ICONST_4: case Constants.ICONST_5: case Constants.ICONST_M1: case Constants.LCONST_0: case Constants.LCONST_1: { break; } case Constants.BIPUSH: case Constants.SIPUSH: { ConstantPushInstruction cpi = (ConstantPushInstruction) inst; result.ints.add((Integer) cpi.getValue()); break; } // Primitive Binary operators. case Constants.DADD: case Constants.DCMPG: case Constants.DCMPL: case Constants.DDIV: case Constants.DMUL: case Constants.DREM: case Constants.DSUB: case Constants.FADD: case Constants.FCMPG: case Constants.FCMPL: case Constants.FDIV: case Constants.FMUL: case Constants.FREM: case Constants.FSUB: case Constants.IADD: case Constants.IAND: case Constants.IDIV: case Constants.IMUL: case Constants.IOR: case Constants.IREM: case Constants.ISHL: case Constants.ISHR: case Constants.ISUB: case Constants.IUSHR: case Constants.IXOR: case Constants.LADD: case Constants.LAND: case Constants.LCMP: case Constants.LDIV: case Constants.LMUL: case Constants.LOR: case Constants.LREM: case Constants.LSHL: case Constants.LSHR: case Constants.LSUB: case Constants.LUSHR: case Constants.LXOR: break; case Constants.LOOKUPSWITCH: case Constants.TABLESWITCH: break; case Constants.ANEWARRAY: case Constants.NEWARRAY: { break; } case Constants.MULTIANEWARRAY: { break; } // push the value at an index in an array case Constants.AALOAD: case Constants.BALOAD: case Constants.CALOAD: case Constants.DALOAD: case Constants.FALOAD: case Constants.IALOAD: case Constants.LALOAD: case Constants.SALOAD: { break; } // Pop the top of stack into an array location case Constants.AASTORE: case Constants.BASTORE: case Constants.CASTORE: case Constants.DASTORE: case Constants.FASTORE: case Constants.IASTORE: case Constants.LASTORE: case Constants.SASTORE: break; case Constants.ARETURN: case Constants.DRETURN: case Constants.FRETURN: case Constants.IRETURN: case Constants.LRETURN: case Constants.RETURN: { break; } // subroutine calls. case Constants.INVOKESTATIC: case Constants.INVOKEVIRTUAL: case Constants.INVOKESPECIAL: case Constants.INVOKEINTERFACE: break; // Throws an exception. case Constants.ATHROW: break; // Opcodes that don't need any modifications. Here for reference case Constants.ACONST_NULL: case Constants.ALOAD: case Constants.ALOAD_0: case Constants.ALOAD_1: case Constants.ALOAD_2: case Constants.ALOAD_3: case Constants.ASTORE: case Constants.ASTORE_0: case Constants.ASTORE_1: case Constants.ASTORE_2: case Constants.ASTORE_3: case Constants.CHECKCAST: case Constants.D2F: // double to float case Constants.D2I: // double to integer case Constants.D2L: // double to long case Constants.DNEG: // Negate double on top of stack case Constants.F2D: // float to double case Constants.F2I: // float to integer case Constants.F2L: // float to long case Constants.FNEG: // Negate float on top of stack case Constants.GOTO: case Constants.GOTO_W: case Constants.I2B: // integer to byte case Constants.I2C: // integer to char case Constants.I2D: // integer to double case Constants.I2F: // integer to float case Constants.I2L: // integer to long case Constants.I2S: // integer to short case Constants.IFNONNULL: case Constants.IFNULL: case Constants.IINC: // increment local variable by a constant case Constants.INEG: // negate integer on top of stack case Constants.JSR: // pushes return address on the stack, case Constants.JSR_W: case Constants.L2D: // long to double case Constants.L2F: // long to float case Constants.L2I: // long to int case Constants.LNEG: // negate long on top of stack case Constants.MONITORENTER: case Constants.MONITOREXIT: case Constants.NEW: case Constants.NOP: case Constants.RET: // this is the internal JSR return break; // Make sure we didn't miss anything default: throw new Error("instruction " + inst + " unsupported"); } } } } return result; }