CodeItem.java revision 2fe6041fa9e2e2eab534a7da086006835c8f59f6
1/* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32package org.jf.dexlib2.dexbacked.raw; 33 34import com.google.common.base.Joiner; 35import com.google.common.collect.Lists; 36import org.jf.dexlib2.VerificationError; 37import org.jf.dexlib2.dexbacked.DexReader; 38import org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction; 39import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator; 40import org.jf.dexlib2.iface.instruction.*; 41import org.jf.dexlib2.iface.instruction.formats.*; 42import org.jf.dexlib2.util.AnnotatedBytes; 43import org.jf.dexlib2.util.ReferenceUtil; 44import org.jf.util.NumberUtils; 45 46import javax.annotation.Nonnull; 47import javax.annotation.Nullable; 48import java.util.List; 49 50public class CodeItem { 51 public static final int REGISTERS_OFFSET = 0; 52 public static final int INS_OFFSET = 2; 53 public static final int OUTS_OFFSET = 4; 54 public static final int TRIES_SIZE_OFFSET = 6; 55 public static final int DEBUG_INFO_OFFSET = 8; 56 public static final int INSTRUCTION_COUNT_OFFSET = 12; 57 public static final int INSTRUCTION_START_OFFSET = 16; 58 59 public static class TryItem { 60 public static final int ITEM_SIZE = 8; 61 62 public static final int START_ADDRESS_OFFSET = 0; 63 public static final int CODE_UNIT_COUNT_OFFSET = 4; 64 public static final int HANDLER_OFFSET = 6; 65 } 66 67 @Nonnull 68 public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { 69 return new SectionAnnotator(annotator, mapItem) { 70 private SectionAnnotator debugInfoAnnotator = null; 71 72 @Override public void annotateSection(@Nonnull AnnotatedBytes out) { 73 debugInfoAnnotator = annotator.getAnnotator(ItemType.DEBUG_INFO_ITEM); 74 super.annotateSection(out); 75 } 76 77 @Nonnull @Override public String getItemName() { 78 return "code_item"; 79 } 80 81 @Override public int getItemAlignment() { 82 return 4; 83 } 84 85 @Override 86 public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { 87 DexReader reader = dexFile.readerAt(out.getCursor()); 88 89 int registers = reader.readUshort(); 90 out.annotate(2, "registers_size = %d", registers); 91 92 int inSize = reader.readUshort(); 93 out.annotate(2, "ins_size = %d", inSize); 94 95 int outSize = reader.readUshort(); 96 out.annotate(2, "outs_size = %d", outSize); 97 98 int triesCount = reader.readUshort(); 99 out.annotate(2, "tries_size = %d", triesCount); 100 101 int debugInfoOffset = reader.readSmallUint(); 102 out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset); 103 104 if (debugInfoOffset != 0) { 105 addDebugInfoIdentity(debugInfoOffset, itemIdentity); 106 } 107 108 int instructionSize = reader.readSmallUint(); 109 out.annotate(4, "insns_size = 0x%x", instructionSize); 110 111 out.annotate(0, "instructions:"); 112 out.indent(); 113 114 int end = reader.getOffset() + instructionSize*2; 115 while (reader.getOffset() < end) { 116 Instruction instruction = DexBackedInstruction.readFrom(reader); 117 118 switch (instruction.getOpcode().format) { 119 case Format10x: 120 annotateInstruction10x(out, instruction); 121 break; 122 case Format35c: 123 annotateInstruction35c(out, (Instruction35c)instruction); 124 break; 125 case Format3rc: 126 annotateInstruction3rc(out, (Instruction3rc)instruction); 127 break; 128 case ArrayPayload: 129 annotateArrayPayload(out, (ArrayPayload)instruction); 130 break; 131 case PackedSwitchPayload: 132 annotatePackedSwitchPayload(out, (PackedSwitchPayload)instruction); 133 break; 134 case SparseSwitchPayload: 135 annotateSparseSwitchPayload(out, (SparseSwitchPayload)instruction); 136 break; 137 default: 138 annotateDefaultInstruction(out, instruction); 139 break; 140 } 141 142 assert reader.getOffset() == out.getCursor(); 143 } 144 out.deindent(); 145 146 if (triesCount > 0) { 147 if ((reader.getOffset() % 4) != 0) { 148 reader.readUshort(); 149 out.annotate(2, "padding"); 150 } 151 152 out.annotate(0, "try_items:"); 153 out.indent(); 154 for (int i=0; i<triesCount; i++) { 155 out.annotate(0, "try_item[%d]:", i); 156 out.indent(); 157 int startAddr = reader.readSmallUint(); 158 out.annotate(4, "start_addr = 0x%x", startAddr); 159 160 int instructionCount = reader.readUshort(); 161 out.annotate(2, "insn_count = 0x%x", instructionCount); 162 163 int handlerOffset = reader.readUshort(); 164 out.annotate(2, "handler_off = 0x%x", handlerOffset); 165 out.deindent(); 166 } 167 out.deindent(); 168 169 int handlerListCount = reader.readSmallUleb128(); 170 out.annotate(0, "encoded_catch_handler_list:"); 171 out.annotateTo(reader.getOffset(), "size = %d", handlerListCount); 172 out.indent(); 173 for (int i=0; i<handlerListCount; i++) { 174 out.annotate(0, "encoded_catch_handler[%d]", i); 175 out.indent(); 176 int handlerCount = reader.readSleb128(); 177 out.annotateTo(reader.getOffset(), "size = %d", handlerCount); 178 boolean hasCatchAll = handlerCount <= 0; 179 handlerCount = Math.abs(handlerCount); 180 if (handlerCount != 0) { 181 out.annotate(0, "handlers:"); 182 out.indent(); 183 for (int j=0; j<handlerCount; j++) { 184 out.annotate(0, "encoded_type_addr_pair[%d]", i); 185 out.indent(); 186 int typeIndex = reader.readSmallUleb128(); 187 out.annotateTo(reader.getOffset(), TypeIdItem.getReferenceAnnotation(dexFile, typeIndex)); 188 189 int handlerAddress = reader.readSmallUleb128(); 190 out.annotateTo(reader.getOffset(), "addr = 0x%x", handlerAddress); 191 out.deindent(); 192 } 193 out.deindent(); 194 } 195 if (hasCatchAll) { 196 int catchAllAddress = reader.readSmallUleb128(); 197 out.annotateTo(reader.getOffset(), "catch_all_addr = 0x%x", catchAllAddress); 198 } 199 out.deindent(); 200 } 201 out.deindent(); 202 } 203 } 204 205 private String formatRegister(int registerNum) { 206 return String.format("v%d", registerNum); 207 } 208 209 private void annotateInstruction10x(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) { 210 out.annotate(2, instruction.getOpcode().name); 211 } 212 213 private void annotateInstruction35c(@Nonnull AnnotatedBytes out, @Nonnull Instruction35c instruction) { 214 List<String> args = Lists.newArrayList(); 215 216 int registerCount = instruction.getRegisterCount(); 217 if (registerCount == 1) { 218 args.add(formatRegister(instruction.getRegisterC())); 219 } else if (registerCount == 2) { 220 args.add(formatRegister(instruction.getRegisterC())); 221 args.add(formatRegister(instruction.getRegisterD())); 222 } else if (registerCount == 3) { 223 args.add(formatRegister(instruction.getRegisterC())); 224 args.add(formatRegister(instruction.getRegisterD())); 225 args.add(formatRegister(instruction.getRegisterE())); 226 } else if (registerCount == 4) { 227 args.add(formatRegister(instruction.getRegisterC())); 228 args.add(formatRegister(instruction.getRegisterD())); 229 args.add(formatRegister(instruction.getRegisterE())); 230 args.add(formatRegister(instruction.getRegisterF())); 231 } else if (registerCount == 5) { 232 args.add(formatRegister(instruction.getRegisterC())); 233 args.add(formatRegister(instruction.getRegisterD())); 234 args.add(formatRegister(instruction.getRegisterE())); 235 args.add(formatRegister(instruction.getRegisterF())); 236 args.add(formatRegister(instruction.getRegisterG())); 237 } 238 239 String reference = ReferenceUtil.getReferenceString(instruction.getReference()); 240 241 out.annotate(6, String.format("%s {%s}, %s", 242 instruction.getOpcode().name, Joiner.on(", ").join(args), reference)); 243 } 244 245 private void annotateInstruction3rc(@Nonnull AnnotatedBytes out, @Nonnull Instruction3rc instruction) { 246 int startRegister = instruction.getStartRegister(); 247 int endRegister = startRegister + instruction.getRegisterCount() - 1; 248 String reference = ReferenceUtil.getReferenceString(instruction.getReference()); 249 out.annotate(6, String.format("%s {%s .. %s}, %s", 250 instruction.getOpcode().name, formatRegister(startRegister), formatRegister(endRegister), 251 reference)); 252 } 253 254 private void annotateDefaultInstruction(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) { 255 List<String> args = Lists.newArrayList(); 256 257 if (instruction instanceof OneRegisterInstruction) { 258 args.add(formatRegister(((OneRegisterInstruction)instruction).getRegisterA())); 259 if (instruction instanceof TwoRegisterInstruction) { 260 args.add(formatRegister(((TwoRegisterInstruction)instruction).getRegisterB())); 261 if (instruction instanceof ThreeRegisterInstruction) { 262 args.add(formatRegister(((ThreeRegisterInstruction)instruction).getRegisterC())); 263 } 264 } 265 } else if (instruction instanceof VerificationErrorInstruction) { 266 args.add(VerificationError.getVerificationErrorName( 267 ((VerificationErrorInstruction)instruction).getVerificationError())); 268 } 269 270 if (instruction instanceof ReferenceInstruction) { 271 args.add(ReferenceUtil.getReferenceString( 272 ((ReferenceInstruction)instruction).getReference())); 273 } else if (instruction instanceof OffsetInstruction) { 274 int offset = ((OffsetInstruction)instruction).getCodeOffset(); 275 String sign = offset>=0?"+":"-"; 276 args.add(String.format("%s0x%x", sign, offset)); 277 } else if (instruction instanceof NarrowLiteralInstruction) { 278 int value = ((NarrowLiteralInstruction)instruction).getNarrowLiteral(); 279 if (NumberUtils.isLikelyFloat(value)) { 280 args.add(String.format("%d # %f", value, Float.intBitsToFloat(value))); 281 } else { 282 args.add(String.format("%d", value)); 283 } 284 } else if (instruction instanceof WideLiteralInstruction) { 285 long value = ((WideLiteralInstruction)instruction).getWideLiteral(); 286 if (NumberUtils.isLikelyDouble(value)) { 287 args.add(String.format("%d # %f", value, Double.longBitsToDouble(value))); 288 } else { 289 args.add(String.format("%d", value)); 290 } 291 } else if (instruction instanceof FieldOffsetInstruction) { 292 int fieldOffset = ((FieldOffsetInstruction)instruction).getFieldOffset(); 293 args.add(String.format("field@0x%x", fieldOffset)); 294 } else if (instruction instanceof VtableIndexInstruction) { 295 int vtableIndex = ((VtableIndexInstruction)instruction).getVtableIndex(); 296 args.add(String.format("vtable@%d", vtableIndex)); 297 } else if (instruction instanceof InlineIndexInstruction) { 298 int inlineIndex = ((InlineIndexInstruction)instruction).getInlineIndex(); 299 args.add(String.format("inline@%d", inlineIndex)); 300 } 301 302 out.annotate(instruction.getCodeUnits()*2, "%s %s", 303 instruction.getOpcode().name, Joiner.on(", ").join(args)); 304 } 305 306 private void annotateArrayPayload(@Nonnull AnnotatedBytes out, @Nonnull ArrayPayload instruction) { 307 List<Number> elements = instruction.getArrayElements(); 308 int elementWidth = instruction.getElementWidth(); 309 310 out.annotate(2, instruction.getOpcode().name); 311 out.indent(); 312 out.annotate(2, "element_width = %d", elementWidth); 313 out.annotate(4, "size = %d", elements.size()); 314 out.annotate(0, "elements:"); 315 out.indent(); 316 for (int i=0; i<elements.size(); i++) { 317 if (elementWidth == 8) { 318 long value = elements.get(i).longValue(); 319 if (NumberUtils.isLikelyDouble(value)) { 320 out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Double.longBitsToDouble(value)); 321 } else { 322 out.annotate(elementWidth, "element[%d] = %d", i, value); 323 } 324 } else { 325 int value = elements.get(i).intValue(); 326 if (NumberUtils.isLikelyFloat(value)) { 327 out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Float.intBitsToFloat(value)); 328 } else { 329 out.annotate(elementWidth, "element[%d] = %d", i, value); 330 } 331 } 332 } 333 if (out.getCursor() % 2 != 0) { 334 out.annotate(1, "padding"); 335 } 336 out.deindent(); 337 out.deindent(); 338 } 339 340 private void annotatePackedSwitchPayload(@Nonnull AnnotatedBytes out, 341 @Nonnull PackedSwitchPayload instruction) { 342 List<? extends SwitchElement> elements = instruction.getSwitchElements(); 343 344 out.annotate(2, instruction.getOpcode().name); 345 out.indent(); 346 347 out.annotate(2, "size = %d", elements.size()); 348 if (elements.size() == 0) { 349 out.annotate(4, "first_key"); 350 } else { 351 out.annotate(4, "first_key = %d", elements.get(0).getKey()); 352 out.annotate(0, "targets:"); 353 out.indent(); 354 for (int i=0; i<elements.size(); i++) { 355 out.annotate(4, "target[%d] = %d", i, elements.get(i).getOffset()); 356 } 357 out.deindent(); 358 } 359 out.deindent(); 360 } 361 362 private void annotateSparseSwitchPayload(@Nonnull AnnotatedBytes out, 363 @Nonnull SparseSwitchPayload instruction) { 364 List<? extends SwitchElement> elements = instruction.getSwitchElements(); 365 366 out.annotate(2, instruction.getOpcode().name); 367 out.indent(); 368 out.annotate(2, "size = %d", elements.size()); 369 if (elements.size() > 0) { 370 out.annotate(0, "keys:"); 371 out.indent(); 372 for (int i=0; i<elements.size(); i++) { 373 out.annotate(4, "key[%d] = %d", i, elements.get(i).getKey()); 374 } 375 out.deindent(); 376 out.annotate(0, "targets:"); 377 out.indent(); 378 for (int i=0; i<elements.size(); i++) { 379 out.annotate(4, "target[%d] = %d", i, elements.get(i).getOffset()); 380 } 381 out.deindent(); 382 } 383 out.deindent(); 384 } 385 386 private void addDebugInfoIdentity(int debugInfoOffset, String methodString) { 387 if (debugInfoAnnotator != null) { 388 debugInfoAnnotator.setItemIdentity(debugInfoOffset, methodString); 389 } 390 } 391 }; 392 } 393} 394