1 /* 2 * Copyright 2019, Google LLC 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google LLC nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 package com.android.tools.smali.dexlib2.dexbacked; 32 33 import com.android.tools.smali.dexlib2.dexbacked.raw.CodeItem; 34 import javax.annotation.Nonnull; 35 36 public class CDexBackedMethodImplementation extends DexBackedMethodImplementation { 37 CDexBackedMethodImplementation( @onnull DexBackedDexFile dexFile, @Nonnull DexBackedMethod method, int codeOffset)38 public CDexBackedMethodImplementation( 39 @Nonnull DexBackedDexFile dexFile, @Nonnull DexBackedMethod method, int codeOffset) { 40 super(dexFile, method, codeOffset); 41 } 42 getInsCount()43 public int getInsCount() { 44 int insCount = (dexFile.getDataBuffer().readUshort(codeOffset) >> CodeItem.CDEX_INS_COUNT_SHIFT) & 0xf; 45 46 if ((getPreheaderFlags() & CodeItem.CDEX_PREHEADER_FLAG_INS_COUNT) != 0) { 47 int preheaderCount = 1; 48 49 if ((getPreheaderFlags() & CodeItem.CDEX_PREHEADER_FLAG_INSTRUCTIONS_SIZE) != 0) { 50 preheaderCount+=2; 51 } 52 if ((getPreheaderFlags() & CodeItem.CDEX_PREHEADER_FLAG_REGISTER_COUNT) != 0) { 53 preheaderCount++; 54 } 55 insCount += dexFile.getDataBuffer().readUshort(codeOffset - 2 * preheaderCount); 56 } 57 return insCount; 58 } 59 60 @Override getRegisterCount()61 public int getRegisterCount() { 62 int registerCount = (dexFile.getDataBuffer().readUshort(codeOffset) >> CodeItem.CDEX_REGISTER_COUNT_SHIFT) & 0xf; 63 64 registerCount += getInsCount(); 65 if ((getPreheaderFlags() & CodeItem.CDEX_PREHEADER_FLAG_REGISTER_COUNT) != 0) { 66 int preheaderCount = 1; 67 if ((getPreheaderFlags() & CodeItem.CDEX_PREHEADER_FLAG_INSTRUCTIONS_SIZE) > 0) { 68 preheaderCount += 2; 69 } 70 registerCount += dexFile.getDataBuffer().readUshort(codeOffset - 2 * preheaderCount); 71 } 72 return registerCount; 73 } 74 75 @Override getInstructionsSize()76 public int getInstructionsSize() { 77 int instructionsSize = dexFile.getDataBuffer().readUshort( 78 codeOffset + CodeItem.CDEX_INSTRUCTIONS_SIZE_AND_PREHEADER_FLAGS_OFFSET) >> 79 CodeItem.CDEX_INSTRUCTIONS_SIZE_SHIFT; 80 81 if ((getPreheaderFlags() & CodeItem.CDEX_PREHEADER_FLAG_INSTRUCTIONS_SIZE) != 0) { 82 instructionsSize += dexFile.getDataBuffer().readUshort(codeOffset - 2); 83 instructionsSize += dexFile.getDataBuffer().readUshort(codeOffset - 4) << 16; 84 } 85 return instructionsSize; 86 } 87 88 @Override getInstructionsStartOffset()89 protected int getInstructionsStartOffset() { 90 return codeOffset + 4; 91 } 92 getPreheaderFlags()93 private int getPreheaderFlags() { 94 return dexFile.getDataBuffer().readUshort(codeOffset + CodeItem.CDEX_INSTRUCTIONS_SIZE_AND_PREHEADER_FLAGS_OFFSET) & 95 CodeItem.CDEX_PREHEADER_FLAGS_MASK; 96 } 97 98 @Override getTriesSize()99 protected int getTriesSize() { 100 int triesCount = (dexFile.getDataBuffer().readUshort(codeOffset) >> CodeItem.CDEX_TRIES_SIZE_SHIFT) & 0xf; 101 if ((getPreheaderFlags() & CodeItem.CDEX_PREHEADER_FLAG_TRIES_COUNT) != 0) { 102 int preheaderCount = Integer.bitCount(getPreheaderFlags()); 103 if ((getPreheaderFlags() & CodeItem.CDEX_PREHEADER_FLAG_INSTRUCTIONS_SIZE) != 0) { 104 // The instructions size preheader is 2 shorts 105 preheaderCount++; 106 } 107 triesCount += dexFile.getDataBuffer().readUshort(codeOffset - 2 * preheaderCount); 108 } 109 return triesCount; 110 } 111 112 @Override getDebugOffset()113 protected int getDebugOffset() { 114 CDexBackedDexFile cdexFile = ((CDexBackedDexFile) dexFile); 115 116 int debugTableItemOffset = (method.methodIndex / 16) * 4; 117 int bitIndex = method.methodIndex % 16; 118 119 int debugInfoOffsetsPos = cdexFile.getDebugInfoOffsetsPos(); 120 int debugTableOffset = debugInfoOffsetsPos + cdexFile.getDebugInfoOffsetsTableOffset(); 121 122 int debugOffsetsOffset = cdexFile.getDataBuffer().readSmallUint(debugTableOffset + debugTableItemOffset); 123 124 DexReader<? extends DexBuffer> reader = cdexFile.getDataBuffer().readerAt(debugInfoOffsetsPos + debugOffsetsOffset); 125 126 int bitMask = reader.readUbyte() << 8; 127 bitMask += reader.readUbyte(); 128 129 if ((bitMask & (1 << bitIndex)) == 0) { 130 return 0; 131 } 132 133 int offsetCount = Integer.bitCount(bitMask & 0xFFFF >> (16-bitIndex)); 134 int baseDebugOffset = cdexFile.getDebugInfoBase(); 135 for (int i=0; i<offsetCount; i++) { 136 baseDebugOffset += reader.readBigUleb128(); 137 } 138 baseDebugOffset += reader.readBigUleb128(); 139 return baseDebugOffset; 140 } 141 } 142