1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License. 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License. 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.command.dump; 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.code.ConcreteMethod; 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.code.Ropper; 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.direct.DirectClassFile; 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.direct.StdAttributeFactory; 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.Member; 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.Method; 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseObserver; 26fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.AccessFlags; 27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.BasicBlock; 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.BasicBlockList; 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.DexTranslationAdvice; 30fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.RopMethod; 31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.TranslationAdvice; 32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.ssa.Optimizer; 33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.ByteArray; 34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex; 35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.IntList; 36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** 38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Dumps the pred/succ graph of methods into a format compatible 39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * with the popular graph utility "dot". 40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class DotDumper implements ParseObserver { 4299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project private DirectClassFile classFile; 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 4499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project private final byte[] bytes; 4599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project private final String filePath; 4699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project private final boolean strictParse; 4799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project private final boolean optimize; 4899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project private final Args args; 49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 5099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project static void dump(byte[] bytes, String filePath, Args args) { 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project new DotDumper(bytes, filePath, args).run(); 52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project DotDumper(byte[] bytes, String filePath, Args args) { 55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.bytes = bytes; 56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.filePath = filePath; 57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.strictParse = args.strictParse; 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.optimize = args.optimize; 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.args = args; 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private void run() { 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ByteArray ba = new ByteArray(bytes); 64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * First, parse the file completely, so we can safely refer to 67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * attributes, etc. 68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project classFile = new DirectClassFile(ba, filePath, strictParse); 70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project classFile.setAttributeFactory(StdAttributeFactory.THE_ONE); 71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project classFile.getMagic(); // Force parsing to happen. 72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Next, reparse it and observe the process. 74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project DirectClassFile liveCf = 75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project new DirectClassFile(ba, filePath, strictParse); 76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project liveCf.setAttributeFactory(StdAttributeFactory.THE_ONE); 77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project liveCf.setObserver(this); 78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project liveCf.getMagic(); // Force parsing to happen. 79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param name method name 83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @return true if this method should be dumped 84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project protected boolean shouldDumpMethod(String name) { 86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return args.method == null || args.method.equals(name); 87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void changeIndent(int indentDelta) { 9099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project // This space intentionally left blank. 91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void parsed(ByteArray bytes, int offset, int len, String human) { 9499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project // This space intentionally left blank. 95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void startParsingMember(ByteArray bytes, int offset, String name, 99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String descriptor) { 10099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project // This space intentionally left blank. 101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void endParsingMember(ByteArray bytes, int offset, String name, 104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String descriptor, Member member) { 105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!(member instanceof Method)) { 106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!shouldDumpMethod(name)) { 110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ConcreteMethod meth = new ConcreteMethod((Method) member, classFile, 114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project true, true); 115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project TranslationAdvice advice = DexTranslationAdvice.THE_ONE; 117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project RopMethod rmeth = 118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Ropper.convert(meth, advice); 119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (optimize) { 121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags()); 122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project rmeth = Optimizer.optimize(rmeth, 123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project BaseDumper.computeParamWidth(meth, isStatic), isStatic, 124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project true, advice); 125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.println("digraph " + name + "{"); 128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.println("\tfirst -> n" 130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project + Hex.u2(rmeth.getFirstLabel()) + ";"); 131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project BasicBlockList blocks = rmeth.getBlocks(); 133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int sz = blocks.size(); 135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < sz; i++) { 136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project BasicBlock bb = blocks.get(i); 137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int label = bb.getLabel(); 138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project IntList successors = bb.getSuccessors(); 139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (successors.size() == 0) { 141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.println("\tn" + Hex.u2(label) + " -> returns;"); 142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else if (successors.size() == 1) { 143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.println("\tn" + Hex.u2(label) + " -> n" 144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project + Hex.u2(successors.get(0)) + ";"); 145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.print("\tn" + Hex.u2(label) + " -> {"); 147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int j = 0; j < successors.size(); j++ ) { 148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int successor = successors.get(j); 149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (successor != bb.getPrimarySuccessor()) { 151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.print(" n" + Hex.u2(successor) + " "); 152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.println("};"); 156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.println("\tn" + Hex.u2(label) + " -> n" 158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project + Hex.u2(bb.getPrimarySuccessor()) 159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project + " [label=\"primary\"];"); 160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.out.println("}"); 166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 168