169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit. 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved. 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License. Alternatively, the contents of this file may be used under 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later. 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis, 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License. 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.bytecode.analysis; 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.PrintStream; 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtClass; 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtMethod; 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.Modifier; 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.NotFoundException; 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.BadBytecode; 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.CodeAttribute; 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.CodeIterator; 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.ConstPool; 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.Descriptor; 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.InstructionPrinter; 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.bytecode.MethodInfo; 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/** 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A utility class for printing a merged view of the frame state and the 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instructions of a method. 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Jason T. Greene 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic final class FramePrinter { 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private final PrintStream stream; 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Constructs a bytecode printer. 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public FramePrinter(PrintStream stream) { 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.stream = stream; 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Prints all the methods declared in the given class. 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static void print(CtClass clazz, PrintStream stream) { 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal (new FramePrinter(stream)).print(clazz); 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Prints all the methods declared in the given class. 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public void print(CtClass clazz) { 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtMethod[] methods = clazz.getDeclaredMethods(); 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < methods.length; i++) { 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal print(methods[i]); 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private String getMethodString(CtMethod method) { 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return Modifier.toString(method.getModifiers()) + " " 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal + method.getReturnType().getName() + " " + method.getName() 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal + Descriptor.toString(method.getSignature()) + ";"; 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Prints the instructions and the frame states of the given method. 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public void print(CtMethod method) { 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.println("\n" + getMethodString(method)); 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal MethodInfo info = method.getMethodInfo2(); 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ConstPool pool = info.getConstPool(); 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeAttribute code = info.getCodeAttribute(); 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (code == null) 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return; 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Frame[] frames; 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal frames = (new Analyzer()).analyze(method.getDeclaringClass(), info); 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (BadBytecode e) { 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int spacing = String.valueOf(code.getCodeLength()).length(); 9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CodeIterator iterator = code.iterator(); 9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (iterator.hasNext()) { 9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int pos; 9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal pos = iterator.next(); 9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (BadBytecode e) { 10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.println(pos + ": " + InstructionPrinter.instructionString(iterator, pos, pool)); 10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal addSpacing(spacing + 3); 10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Frame frame = frames[pos]; 10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (frame == null) { 10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.println("--DEAD CODE--"); 10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal continue; 11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal printStack(frame); 11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal addSpacing(spacing + 3); 11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal printLocals(frame); 11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void printStack(Frame frame) { 12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.print("stack ["); 12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int top = frame.getTopIndex(); 12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i <= top; i++) { 12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (i > 0) 12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.print(", "); 12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type type = frame.getStack(i); 12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.print(type); 12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.println("]"); 12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void printLocals(Frame frame) { 13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.print("locals ["); 13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int length = frame.localsLength(); 13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < length; i++) { 13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (i > 0) 13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.print(", "); 13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type type = frame.getLocal(i); 13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.print(type == null ? "empty" : type.toString()); 13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.println("]"); 14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void addSpacing(int count) { 14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (count-- > 0) 14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal stream.print(' '); 14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 148