• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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