1 /* 2 * Copyright 2013, 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.raw; 32 33 import com.android.tools.smali.dexlib2.ReferenceType; 34 import com.android.tools.smali.dexlib2.VerificationError; 35 import com.android.tools.smali.dexlib2.dexbacked.DexBuffer; 36 import com.android.tools.smali.dexlib2.dexbacked.instruction.DexBackedInstruction; 37 import com.android.tools.smali.dexlib2.dexbacked.raw.util.DexAnnotator; 38 import com.android.tools.smali.dexlib2.iface.instruction.FieldOffsetInstruction; 39 import com.android.tools.smali.dexlib2.iface.instruction.InlineIndexInstruction; 40 import com.android.tools.smali.dexlib2.iface.instruction.Instruction; 41 import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction; 42 import com.android.tools.smali.dexlib2.iface.instruction.OffsetInstruction; 43 import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction; 44 import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction; 45 import com.android.tools.smali.dexlib2.iface.instruction.SwitchElement; 46 import com.android.tools.smali.dexlib2.iface.instruction.ThreeRegisterInstruction; 47 import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction; 48 import com.android.tools.smali.dexlib2.iface.instruction.VerificationErrorInstruction; 49 import com.android.tools.smali.dexlib2.iface.instruction.VtableIndexInstruction; 50 import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction; 51 import com.android.tools.smali.dexlib2.iface.instruction.formats.ArrayPayload; 52 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c; 53 import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc; 54 import com.android.tools.smali.dexlib2.iface.instruction.formats.PackedSwitchPayload; 55 import com.android.tools.smali.dexlib2.iface.instruction.formats.SparseSwitchPayload; 56 import com.android.tools.smali.dexlib2.util.AnnotatedBytes; 57 import com.android.tools.smali.util.ExceptionWithContext; 58 import com.android.tools.smali.util.NumberUtils; 59 import com.android.tools.smali.util.StringUtils; 60 import com.android.tools.smali.dexlib2.dexbacked.CDexBackedDexFile; 61 import com.android.tools.smali.dexlib2.dexbacked.DexReader; 62 import com.android.tools.smali.dexlib2.formatter.DexFormatter; 63 import com.android.tools.smali.dexlib2.iface.reference.Reference; 64 import com.android.tools.smali.dexlib2.iface.reference.StringReference; 65 66 import javax.annotation.Nonnull; 67 import javax.annotation.Nullable; 68 import java.util.ArrayList; 69 import java.util.List; 70 71 public class CodeItem { 72 public static final int REGISTERS_OFFSET = 0; 73 public static final int INS_OFFSET = 2; 74 public static final int OUTS_OFFSET = 4; 75 public static final int TRIES_SIZE_OFFSET = 6; 76 public static final int DEBUG_INFO_OFFSET = 8; 77 public static final int INSTRUCTION_COUNT_OFFSET = 12; 78 public static final int INSTRUCTION_START_OFFSET = 16; 79 80 public static int CDEX_TRIES_SIZE_SHIFT = 0; 81 public static int CDEX_OUTS_COUNT_SHIFT = 4; 82 public static int CDEX_INS_COUNT_SHIFT = 8; 83 public static int CDEX_REGISTER_COUNT_SHIFT = 12; 84 85 public static int CDEX_INSTRUCTIONS_SIZE_AND_PREHEADER_FLAGS_OFFSET = 2; 86 public static int CDEX_INSTRUCTIONS_SIZE_SHIFT = 5; 87 public static int CDEX_PREHEADER_FLAGS_MASK = 0x1f; 88 public static int CDEX_PREHEADER_FLAG_REGISTER_COUNT = 1 << 0; 89 public static int CDEX_PREHEADER_FLAG_INS_COUNT = 1 << 1; 90 public static int CDEX_PREHEADER_FLAG_OUTS_COUNT = 1 << 2; 91 public static int CDEX_PREHEADER_FLAG_TRIES_COUNT = 1 << 3; 92 public static int CDEX_PREHEADER_FLAG_INSTRUCTIONS_SIZE = 1 << 4; 93 94 public static class TryItem { 95 public static final int ITEM_SIZE = 8; 96 97 public static final int START_ADDRESS_OFFSET = 0; 98 public static final int CODE_UNIT_COUNT_OFFSET = 4; 99 public static final int HANDLER_OFFSET = 6; 100 } 101 makeAnnotator(@onnull DexAnnotator annotator, @Nonnull MapItem mapItem)102 public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { 103 if (annotator.dexFile instanceof CDexBackedDexFile) { 104 return makeAnnotatorForCDex(annotator, mapItem); 105 } else { 106 return makeAnnotatorForDex(annotator, mapItem); 107 } 108 } 109 110 @Nonnull makeAnnotatorForDex(@onnull DexAnnotator annotator, @Nonnull MapItem mapItem)111 private static SectionAnnotator makeAnnotatorForDex(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { 112 return new CodeItemAnnotator(annotator, mapItem); 113 } 114 115 @Nonnull makeAnnotatorForCDex(@onnull DexAnnotator annotator, @Nonnull MapItem mapItem)116 private static SectionAnnotator makeAnnotatorForCDex(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { 117 return new CodeItemAnnotator(annotator, mapItem) { 118 119 private List<Integer> sortedItems; 120 121 @Override public void annotateSection(@Nonnull AnnotatedBytes out) { 122 sortedItems = new ArrayList<>(itemIdentities.keySet()); 123 sortedItems.sort(Integer::compareTo); 124 125 //debugInfoAnnotator = annotator.getAnnotator(ItemType.DEBUG_INFO_ITEM); 126 out.moveTo(sectionOffset); 127 annotateSectionInner(out, itemIdentities.size()); 128 } 129 130 @Override 131 protected int getItemOffset(int itemIndex, int currentOffset) { 132 return sortedItems.get(itemIndex); 133 } 134 135 @Override 136 protected PreInstructionInfo annotatePreInstructionFields( 137 @Nonnull AnnotatedBytes out, @Nonnull DexReader<? extends DexBuffer> reader, @Nullable String itemIdentity) { 138 int sizeFields = reader.readUshort(); 139 140 int triesCount = (sizeFields >> CDEX_TRIES_SIZE_SHIFT) & 0xf; 141 int outsCount = (sizeFields >> CDEX_OUTS_COUNT_SHIFT) & 0xf; 142 int insCount = (sizeFields >> CDEX_INS_COUNT_SHIFT) & 0xf; 143 int registerCount = (sizeFields >> CDEX_REGISTER_COUNT_SHIFT) & 0xf; 144 145 int startOffset = out.getCursor(); 146 147 out.annotate(2, "tries_size = %d", triesCount); 148 out.annotate(0, "outs_size = %d", outsCount); 149 out.annotate(0, "ins_size = %d", insCount); 150 out.annotate(0, "registers_size = %d", registerCount); 151 152 int instructionsSizeAndPreheaderFlags = reader.readUshort(); 153 154 int instructionsSize = instructionsSizeAndPreheaderFlags >> CDEX_INSTRUCTIONS_SIZE_SHIFT; 155 156 out.annotate(2, "insns_size = %d", instructionsSize); 157 158 int instructionsStartOffset = out.getCursor(); 159 int preheaderOffset = startOffset; 160 161 int totalTriesCount = triesCount; 162 int totalInstructionsSize = instructionsSize; 163 164 if ((instructionsSizeAndPreheaderFlags & CDEX_PREHEADER_FLAGS_MASK) != 0) { 165 int preheaderCount = Integer.bitCount( 166 instructionsSizeAndPreheaderFlags & CDEX_PREHEADER_FLAGS_MASK); 167 if ((instructionsSizeAndPreheaderFlags & CDEX_PREHEADER_FLAG_INSTRUCTIONS_SIZE) != 0) { 168 // The instructions size preheader is 2 shorts 169 preheaderCount++; 170 } 171 172 out.moveTo((startOffset - 2 * preheaderCount)); 173 out.deindent(); 174 out.annotate(0, "[preheader for next code_item]"); 175 out.indent(); 176 out.moveTo(instructionsStartOffset); 177 } 178 179 if ((instructionsSizeAndPreheaderFlags & CDEX_PREHEADER_FLAG_INSTRUCTIONS_SIZE) != 0) { 180 out.annotate(0, "insns_size_preheader_flag=1"); 181 preheaderOffset -= 2; 182 reader.setOffset(preheaderOffset); 183 int extraInstructionsSize = reader.readUshort(); 184 preheaderOffset -= 2; 185 reader.setOffset(preheaderOffset); 186 extraInstructionsSize += reader.readUshort(); 187 188 out.moveTo(preheaderOffset); 189 totalInstructionsSize += extraInstructionsSize; 190 out.annotate(2, "insns_size = %d + %d = %d", 191 instructionsSize, extraInstructionsSize, instructionsSize + extraInstructionsSize); 192 out.moveTo(instructionsStartOffset); 193 } 194 195 if ((instructionsSizeAndPreheaderFlags & CDEX_PREHEADER_FLAG_REGISTER_COUNT) != 0) { 196 out.annotate(0, "registers_size_preheader_flag=1"); 197 preheaderOffset -= 2; 198 out.moveTo(preheaderOffset); 199 reader.setOffset(preheaderOffset); 200 int extraRegisterCount = reader.readUshort(); 201 out.annotate(2, "registers_size = %d + %d = %d", 202 registerCount, extraRegisterCount, registerCount + extraRegisterCount); 203 out.moveTo(instructionsStartOffset); 204 } 205 if ((instructionsSizeAndPreheaderFlags & CDEX_PREHEADER_FLAG_INS_COUNT) != 0) { 206 out.annotate(0, "ins_size_preheader_flag=1"); 207 preheaderOffset -= 2; 208 out.moveTo(preheaderOffset); 209 reader.setOffset(preheaderOffset); 210 int extraInsCount = reader.readUshort(); 211 out.annotate(2, "ins_size = %d + %d = %d", 212 insCount, extraInsCount, insCount + extraInsCount); 213 out.moveTo(instructionsStartOffset); 214 } 215 if ((instructionsSizeAndPreheaderFlags & CDEX_PREHEADER_FLAG_OUTS_COUNT) != 0) { 216 out.annotate(0, "outs_size_preheader_flag=1"); 217 preheaderOffset -= 2; 218 out.moveTo(preheaderOffset); 219 reader.setOffset(preheaderOffset); 220 int extraOutsCount = reader.readUshort(); 221 out.annotate(2, "outs_size = %d + %d = %d", 222 outsCount, extraOutsCount, outsCount + extraOutsCount); 223 out.moveTo(instructionsStartOffset); 224 } 225 if ((instructionsSizeAndPreheaderFlags & CDEX_PREHEADER_FLAG_TRIES_COUNT) != 0) { 226 out.annotate(0, "tries_size_preheader_flag=1"); 227 preheaderOffset -= 2; 228 out.moveTo(preheaderOffset); 229 reader.setOffset(preheaderOffset); 230 int extraTriesCount = reader.readUshort(); 231 totalTriesCount += extraTriesCount; 232 out.annotate(2, "tries_size = %d + %d = %d", 233 triesCount, extraTriesCount, triesCount + extraTriesCount); 234 out.moveTo(instructionsStartOffset); 235 } 236 237 reader.setOffset(instructionsStartOffset); 238 239 return new PreInstructionInfo(totalTriesCount, totalInstructionsSize); 240 } 241 }; 242 } 243 244 private static class CodeItemAnnotator extends SectionAnnotator { 245 private SectionAnnotator debugInfoAnnotator; 246 CodeItemAnnotator(@onnull DexAnnotator annotator, @Nonnull MapItem mapItem)247 public CodeItemAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { 248 super(annotator, mapItem); 249 } 250 getItemName()251 @Nonnull @Override public String getItemName() { 252 return "code_item"; 253 } 254 getItemAlignment()255 @Override public int getItemAlignment() { 256 return 4; 257 } 258 259 protected class PreInstructionInfo { 260 public int triesCount; 261 public int instructionSize; 262 PreInstructionInfo(int triesCount, int instructionSize)263 public PreInstructionInfo(int triesCount, int instructionSize) { 264 this.triesCount = triesCount; 265 this.instructionSize = instructionSize; 266 } 267 } 268 annotatePreInstructionFields( @onnull AnnotatedBytes out, @Nonnull DexReader<? extends DexBuffer> reader, @Nullable String itemIdentity)269 protected PreInstructionInfo annotatePreInstructionFields( 270 @Nonnull AnnotatedBytes out, @Nonnull DexReader<? extends DexBuffer> reader, @Nullable String itemIdentity) { 271 272 int registers = reader.readUshort(); 273 out.annotate(2, "registers_size = %d", registers); 274 275 int inSize = reader.readUshort(); 276 out.annotate(2, "ins_size = %d", inSize); 277 278 int outSize = reader.readUshort(); 279 out.annotate(2, "outs_size = %d", outSize); 280 281 int triesCount = reader.readUshort(); 282 out.annotate(2, "tries_size = %d", triesCount); 283 284 int debugInfoOffset = reader.readInt(); 285 out.annotate(4, "debug_info_off = 0x%x", debugInfoOffset); 286 287 if (debugInfoOffset > 0) { 288 addDebugInfoIdentity(debugInfoOffset, itemIdentity); 289 } 290 291 int instructionSize = reader.readSmallUint(); 292 out.annotate(4, "insns_size = 0x%x", instructionSize); 293 294 return new PreInstructionInfo(triesCount, instructionSize); 295 } 296 annotateInstructions( @onnull AnnotatedBytes out, @Nonnull DexReader<? extends DexBuffer> reader, int instructionSize)297 protected void annotateInstructions( 298 @Nonnull AnnotatedBytes out, 299 @Nonnull DexReader<? extends DexBuffer> reader, 300 int instructionSize) { 301 302 out.annotate(0, "instructions:"); 303 out.indent(); 304 305 out.setLimit(out.getCursor(), out.getCursor() + instructionSize * 2); 306 307 int end = reader.getOffset() + instructionSize*2; 308 try { 309 while (reader.getOffset() < end) { 310 Instruction instruction = DexBackedInstruction.readFrom(dexFile, reader); 311 312 // if we read past the end of the instruction list 313 if (reader.getOffset() > end) { 314 out.annotateTo(end, "truncated instruction"); 315 reader.setOffset(end); 316 } else { 317 switch (instruction.getOpcode().format) { 318 case Format10x: 319 annotateInstruction10x(out, instruction); 320 break; 321 case Format35c: 322 annotateInstruction35c(out, (Instruction35c)instruction); 323 break; 324 case Format3rc: 325 annotateInstruction3rc(out, (Instruction3rc)instruction); 326 break; 327 case ArrayPayload: 328 annotateArrayPayload(out, (ArrayPayload)instruction); 329 break; 330 case PackedSwitchPayload: 331 annotatePackedSwitchPayload(out, (PackedSwitchPayload)instruction); 332 break; 333 case SparseSwitchPayload: 334 annotateSparseSwitchPayload(out, (SparseSwitchPayload)instruction); 335 break; 336 default: 337 annotateDefaultInstruction(out, instruction); 338 break; 339 } 340 } 341 342 assert reader.getOffset() == out.getCursor(); 343 } 344 } catch (ExceptionWithContext ex) { 345 ex.printStackTrace(System.err); 346 out.annotate(0, "annotation error: %s", ex.getMessage()); 347 out.moveTo(end); 348 reader.setOffset(end); 349 } finally { 350 out.clearLimit(); 351 out.deindent(); 352 } 353 } 354 annotatePostInstructionFields(@onnull AnnotatedBytes out, @Nonnull DexReader<? extends DexBuffer> reader, int triesCount)355 protected void annotatePostInstructionFields(@Nonnull AnnotatedBytes out, 356 @Nonnull DexReader<? extends DexBuffer> reader, 357 int triesCount) { 358 if (triesCount > 0) { 359 if ((reader.getOffset() % 4) != 0) { 360 reader.readUshort(); 361 out.annotate(2, "padding"); 362 } 363 364 out.annotate(0, "try_items:"); 365 out.indent(); 366 try { 367 for (int i = 0; i < triesCount; i++) { 368 out.annotate(0, "try_item[%d]:", i); 369 out.indent(); 370 try { 371 int startAddr = reader.readSmallUint(); 372 out.annotate(4, "start_addr = 0x%x", startAddr); 373 374 int instructionCount = reader.readUshort(); 375 out.annotate(2, "insn_count = 0x%x", instructionCount); 376 377 int handlerOffset = reader.readUshort(); 378 out.annotate(2, "handler_off = 0x%x", handlerOffset); 379 } finally { 380 out.deindent(); 381 } 382 } 383 } finally { 384 out.deindent(); 385 } 386 387 int handlerListCount = reader.readSmallUleb128(); 388 out.annotate(0, "encoded_catch_handler_list:"); 389 out.annotateTo(reader.getOffset(), "size = %d", handlerListCount); 390 out.indent(); 391 try { 392 for (int i = 0; i < handlerListCount; i++) { 393 out.annotate(0, "encoded_catch_handler[%d]", i); 394 out.indent(); 395 try { 396 int handlerCount = reader.readSleb128(); 397 out.annotateTo(reader.getOffset(), "size = %d", handlerCount); 398 boolean hasCatchAll = handlerCount <= 0; 399 handlerCount = Math.abs(handlerCount); 400 if (handlerCount != 0) { 401 out.annotate(0, "handlers:"); 402 out.indent(); 403 try { 404 for (int j = 0; j < handlerCount; j++) { 405 out.annotate(0, "encoded_type_addr_pair[%d]", i); 406 out.indent(); 407 try { 408 int typeIndex = reader.readSmallUleb128(); 409 out.annotateTo(reader.getOffset(), TypeIdItem.getReferenceAnnotation(dexFile, typeIndex)); 410 411 int handlerAddress = reader.readSmallUleb128(); 412 out.annotateTo(reader.getOffset(), "addr = 0x%x", handlerAddress); 413 } finally { 414 out.deindent(); 415 } 416 } 417 } finally { 418 out.deindent(); 419 } 420 } 421 if (hasCatchAll) { 422 int catchAllAddress = reader.readSmallUleb128(); 423 out.annotateTo(reader.getOffset(), "catch_all_addr = 0x%x", catchAllAddress); 424 } 425 } finally { 426 out.deindent(); 427 } 428 } 429 } finally { 430 out.deindent(); 431 } 432 } 433 } 434 435 @Override annotateItem(@onnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity)436 public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { 437 try { 438 DexReader<? extends DexBuffer> reader = dexFile.getBuffer().readerAt(out.getCursor()); 439 440 PreInstructionInfo info = annotatePreInstructionFields(out, reader, itemIdentity); 441 annotateInstructions(out, reader, info.instructionSize); 442 annotatePostInstructionFields(out, reader, info.triesCount); 443 } catch (ExceptionWithContext ex) { 444 out.annotate(0, "annotation error: %s", ex.getMessage()); 445 } 446 } 447 formatRegister(int registerNum)448 private String formatRegister(int registerNum) { 449 return String.format("v%d", registerNum); 450 } 451 annotateInstruction10x(@onnull AnnotatedBytes out, @Nonnull Instruction instruction)452 private void annotateInstruction10x(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) { 453 out.annotate(2, instruction.getOpcode().name); 454 } 455 annotateInstruction35c(@onnull AnnotatedBytes out, @Nonnull Instruction35c instruction)456 private void annotateInstruction35c(@Nonnull AnnotatedBytes out, @Nonnull Instruction35c instruction) { 457 List<String> args = new ArrayList<>(); 458 459 int registerCount = instruction.getRegisterCount(); 460 if (registerCount == 1) { 461 args.add(formatRegister(instruction.getRegisterC())); 462 } else if (registerCount == 2) { 463 args.add(formatRegister(instruction.getRegisterC())); 464 args.add(formatRegister(instruction.getRegisterD())); 465 } else if (registerCount == 3) { 466 args.add(formatRegister(instruction.getRegisterC())); 467 args.add(formatRegister(instruction.getRegisterD())); 468 args.add(formatRegister(instruction.getRegisterE())); 469 } else if (registerCount == 4) { 470 args.add(formatRegister(instruction.getRegisterC())); 471 args.add(formatRegister(instruction.getRegisterD())); 472 args.add(formatRegister(instruction.getRegisterE())); 473 args.add(formatRegister(instruction.getRegisterF())); 474 } else if (registerCount == 5) { 475 args.add(formatRegister(instruction.getRegisterC())); 476 args.add(formatRegister(instruction.getRegisterD())); 477 args.add(formatRegister(instruction.getRegisterE())); 478 args.add(formatRegister(instruction.getRegisterF())); 479 args.add(formatRegister(instruction.getRegisterG())); 480 } 481 482 out.annotate(6, String.format("%s {%s}, %s", 483 instruction.getOpcode().name, StringUtils.join(args, ", "), instruction.getReference())); 484 } 485 annotateInstruction3rc(@onnull AnnotatedBytes out, @Nonnull Instruction3rc instruction)486 private void annotateInstruction3rc(@Nonnull AnnotatedBytes out, @Nonnull Instruction3rc instruction) { 487 int startRegister = instruction.getStartRegister(); 488 int endRegister = startRegister + instruction.getRegisterCount() - 1; 489 out.annotate(6, String.format("%s {%s .. %s}, %s", 490 instruction.getOpcode().name, formatRegister(startRegister), formatRegister(endRegister), 491 instruction.getReference())); 492 } 493 annotateDefaultInstruction(@onnull AnnotatedBytes out, @Nonnull Instruction instruction)494 private void annotateDefaultInstruction(@Nonnull AnnotatedBytes out, @Nonnull Instruction instruction) { 495 List<String> args = new ArrayList<>(); 496 497 if (instruction instanceof OneRegisterInstruction) { 498 args.add(formatRegister(((OneRegisterInstruction)instruction).getRegisterA())); 499 if (instruction instanceof TwoRegisterInstruction) { 500 args.add(formatRegister(((TwoRegisterInstruction)instruction).getRegisterB())); 501 if (instruction instanceof ThreeRegisterInstruction) { 502 args.add(formatRegister(((ThreeRegisterInstruction)instruction).getRegisterC())); 503 } 504 } 505 } else if (instruction instanceof VerificationErrorInstruction) { 506 String verificationError = VerificationError.getVerificationErrorName( 507 ((VerificationErrorInstruction) instruction).getVerificationError()); 508 if (verificationError != null) { 509 args.add(verificationError); 510 } else { 511 args.add("invalid verification error type"); 512 } 513 } 514 515 if (instruction instanceof ReferenceInstruction) { 516 ReferenceInstruction referenceInstruction = ((ReferenceInstruction)instruction); 517 Reference reference = ((ReferenceInstruction)instruction).getReference(); 518 519 String referenceString; 520 if (referenceInstruction.getReferenceType() == ReferenceType.STRING) { 521 referenceString = DexFormatter.INSTANCE.getQuotedString((StringReference)reference); 522 } else { 523 referenceString = referenceInstruction.getReference().toString(); 524 } 525 526 args.add(referenceString); 527 } else if (instruction instanceof OffsetInstruction) { 528 int offset = ((OffsetInstruction)instruction).getCodeOffset(); 529 String sign = offset>=0?"+":"-"; 530 args.add(String.format("%s0x%x", sign, Math.abs(offset))); 531 } else if (instruction instanceof NarrowLiteralInstruction) { 532 int value = ((NarrowLiteralInstruction)instruction).getNarrowLiteral(); 533 if (NumberUtils.isLikelyFloat(value)) { 534 args.add(String.format("%d # %f", value, Float.intBitsToFloat(value))); 535 } else { 536 args.add(String.format("%d", value)); 537 } 538 } else if (instruction instanceof WideLiteralInstruction) { 539 long value = ((WideLiteralInstruction)instruction).getWideLiteral(); 540 if (NumberUtils.isLikelyDouble(value)) { 541 args.add(String.format("%d # %f", value, Double.longBitsToDouble(value))); 542 } else { 543 args.add(String.format("%d", value)); 544 } 545 } else if (instruction instanceof FieldOffsetInstruction) { 546 int fieldOffset = ((FieldOffsetInstruction)instruction).getFieldOffset(); 547 args.add(String.format("field@0x%x", fieldOffset)); 548 } else if (instruction instanceof VtableIndexInstruction) { 549 int vtableIndex = ((VtableIndexInstruction)instruction).getVtableIndex(); 550 args.add(String.format("vtable@%d", vtableIndex)); 551 } else if (instruction instanceof InlineIndexInstruction) { 552 int inlineIndex = ((InlineIndexInstruction)instruction).getInlineIndex(); 553 args.add(String.format("inline@%d", inlineIndex)); 554 } 555 556 out.annotate(instruction.getCodeUnits()*2, "%s %s", 557 instruction.getOpcode().name, StringUtils.join(args, ", ")); 558 } 559 annotateArrayPayload(@onnull AnnotatedBytes out, @Nonnull ArrayPayload instruction)560 private void annotateArrayPayload(@Nonnull AnnotatedBytes out, @Nonnull ArrayPayload instruction) { 561 List<Number> elements = instruction.getArrayElements(); 562 int elementWidth = instruction.getElementWidth(); 563 564 out.annotate(2, instruction.getOpcode().name); 565 out.indent(); 566 out.annotate(2, "element_width = %d", elementWidth); 567 out.annotate(4, "size = %d", elements.size()); 568 if (elements.size() > 0) { 569 out.annotate(0, "elements:"); 570 } 571 out.indent(); 572 if (elements.size() > 0) { 573 for (int i = 0; i < elements.size(); i++) { 574 if (elementWidth == 8) { 575 long value = elements.get(i).longValue(); 576 if (NumberUtils.isLikelyDouble(value)) { 577 out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Double.longBitsToDouble(value)); 578 } else { 579 out.annotate(elementWidth, "element[%d] = %d", i, value); 580 } 581 } else { 582 int value = elements.get(i).intValue(); 583 if (NumberUtils.isLikelyFloat(value)) { 584 out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Float.intBitsToFloat(value)); 585 } else { 586 out.annotate(elementWidth, "element[%d] = %d", i, value); 587 } 588 } 589 } 590 } 591 if (out.getCursor() % 2 != 0) { 592 out.annotate(1, "padding"); 593 } 594 out.deindent(); 595 out.deindent(); 596 } 597 annotatePackedSwitchPayload(@onnull AnnotatedBytes out, @Nonnull PackedSwitchPayload instruction)598 private void annotatePackedSwitchPayload(@Nonnull AnnotatedBytes out, 599 @Nonnull PackedSwitchPayload instruction) { 600 List<? extends SwitchElement> elements = instruction.getSwitchElements(); 601 602 out.annotate(2, instruction.getOpcode().name); 603 out.indent(); 604 605 out.annotate(2, "size = %d", elements.size()); 606 if (elements.size() == 0) { 607 out.annotate(4, "first_key"); 608 } else { 609 out.annotate(4, "first_key = %d", elements.get(0).getKey()); 610 out.annotate(0, "targets:"); 611 out.indent(); 612 for (int i=0; i<elements.size(); i++) { 613 out.annotate(4, "target[%d] = %d", i, elements.get(i).getOffset()); 614 } 615 out.deindent(); 616 } 617 out.deindent(); 618 } 619 annotateSparseSwitchPayload(@onnull AnnotatedBytes out, @Nonnull SparseSwitchPayload instruction)620 private void annotateSparseSwitchPayload(@Nonnull AnnotatedBytes out, 621 @Nonnull SparseSwitchPayload instruction) { 622 List<? extends SwitchElement> elements = instruction.getSwitchElements(); 623 624 out.annotate(2, instruction.getOpcode().name); 625 out.indent(); 626 out.annotate(2, "size = %d", elements.size()); 627 if (elements.size() > 0) { 628 out.annotate(0, "keys:"); 629 out.indent(); 630 for (int i=0; i<elements.size(); i++) { 631 out.annotate(4, "key[%d] = %d", i, elements.get(i).getKey()); 632 } 633 out.deindent(); 634 out.annotate(0, "targets:"); 635 out.indent(); 636 for (int i=0; i<elements.size(); i++) { 637 out.annotate(4, "target[%d] = %d", i, elements.get(i).getOffset()); 638 } 639 out.deindent(); 640 } 641 out.deindent(); 642 } 643 addDebugInfoIdentity(int debugInfoOffset, String methodString)644 private void addDebugInfoIdentity(int debugInfoOffset, String methodString) { 645 if (debugInfoAnnotator != null) { 646 debugInfoAnnotator.setItemIdentity(debugInfoOffset, methodString); 647 } 648 } 649 } 650 } 651