Home | History | Annotate | Download | only in dexlib
      1 /*
      2  * [The "BSD licence"]
      3  * Copyright (c) 2010 Ben Gruver (JesusFreke)
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 package org.jf.dexlib;
     30 
     31 import org.jf.dexlib.Debug.DebugInstructionIterator;
     32 import org.jf.dexlib.Debug.DebugOpcode;
     33 import org.jf.dexlib.Util.AnnotatedOutput;
     34 import org.jf.dexlib.Util.ByteArrayInput;
     35 import org.jf.dexlib.Util.Input;
     36 import org.jf.dexlib.Util.Leb128Utils;
     37 
     38 import java.util.ArrayList;
     39 import java.util.List;
     40 
     41 public class DebugInfoItem extends Item<DebugInfoItem> {
     42     private int lineStart;
     43     private StringIdItem[] parameterNames;
     44     private byte[] encodedDebugInfo;
     45     private Item[] referencedItems;
     46 
     47     private CodeItem parent = null;
     48 
     49     /**
     50      * Creates a new uninitialized <code>DebugInfoInfo</code>
     51      * @param dexFile The <code>DexFile</code> that this item belongs to
     52      */
     53     public DebugInfoItem(DexFile dexFile) {
     54         super(dexFile);
     55     }
     56 
     57     /**
     58      * Creates a new <code>DebugInfoItem</code> with the given values
     59      * @param dexFile The <code>DexFile</code> that this item belongs to
     60      * @param lineStart the initial value for the line number register for the debug info machine
     61      * @param parameterNames an array of the names of the associated method's parameters. The entire parameter
     62      * can be null if no parameter info is available, or any element can be null to indicate no info for that parameter
     63      * @param encodedDebugInfo the debug info, encoded as a byte array
     64      * @param referencedItems an array of the items referenced by instructions, in order of occurance in the encoded
     65      * debug info
     66      */
     67     private DebugInfoItem(DexFile dexFile,
     68                          int lineStart,
     69                          StringIdItem[] parameterNames,
     70                          byte[] encodedDebugInfo,
     71                          Item[] referencedItems) {
     72         super(dexFile);
     73         this.lineStart = lineStart;
     74         this.parameterNames = parameterNames;
     75         this.encodedDebugInfo = encodedDebugInfo;
     76         this.referencedItems = referencedItems;
     77     }
     78 
     79     /**
     80      * Returns a new <code>DebugInfoItem</code> with the given values
     81      * @param dexFile The <code>DexFile</code> that this item belongs to
     82      * @param lineStart the initial value for the line number register for the debug info machine
     83      * @param parameterNames an array of the names of the associated method's parameters. The entire parameter
     84      * can be null if no parameter info is available, or any element can be null to indicate no info for that parameter
     85      * @param encodedDebugInfo the debug info, encoded as a byte array
     86      * @param referencedItems an array of the items referenced by instructions, in order of occurance in the encoded
     87      * debug info
     88      * @return a new <code>DebugInfoItem</code> with the given values
     89      */
     90     public static DebugInfoItem internDebugInfoItem(DexFile dexFile,
     91                          int lineStart,
     92                          StringIdItem[] parameterNames,
     93                          byte[] encodedDebugInfo,
     94                          Item[] referencedItems) {
     95         DebugInfoItem debugInfoItem = new DebugInfoItem(dexFile, lineStart, parameterNames, encodedDebugInfo,
     96                 referencedItems);
     97         return dexFile.DebugInfoItemsSection.intern(debugInfoItem);
     98     }
     99 
    100     /** {@inheritDoc} */
    101     protected void readItem(Input in, ReadContext readContext) {
    102         lineStart = in.readUnsignedLeb128();
    103         parameterNames = new StringIdItem[in.readUnsignedLeb128()];
    104         IndexedSection<StringIdItem> stringIdSection = dexFile.StringIdsSection;
    105         for (int i=0; i<parameterNames.length; i++) {
    106             parameterNames[i] = stringIdSection.getOptionalItemByIndex(in.readUnsignedLeb128() - 1);
    107         }
    108 
    109         int start = in.getCursor();
    110         final List<Item> referencedItemsList = new ArrayList<Item>(50);
    111         DebugInstructionIterator.IterateInstructions(in,
    112                 new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() {
    113                     @Override
    114                     public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex,
    115                                                   int typeIndex, boolean registerIsSigned) {
    116                         if (nameIndex != -1) {
    117                             referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
    118                         }
    119                         if (typeIndex != -1) {
    120                             referencedItemsList.add(dexFile.TypeIdsSection.getItemByIndex(typeIndex));
    121                         }
    122                     }
    123 
    124                     @Override
    125                     public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNume,
    126                                                           int nameIndex, int typeIndex, int signatureIndex,
    127                                                           boolean registerIsSigned) {
    128                         if (nameIndex != -1) {
    129                             referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
    130                         }
    131                         if (typeIndex != -1) {
    132                             referencedItemsList.add(dexFile.TypeIdsSection.getItemByIndex(typeIndex));
    133                         }
    134                         if (signatureIndex != -1) {
    135                             referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(signatureIndex));
    136                         }
    137                     }
    138 
    139                     @Override
    140                     public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
    141                         if (nameIndex != -1) {
    142                             referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
    143                         }
    144                     }
    145                 });
    146 
    147         referencedItems = new Item[referencedItemsList.size()];
    148         referencedItemsList.toArray(referencedItems);
    149 
    150         int length = in.getCursor() - start;
    151         in.setCursor(start);
    152         encodedDebugInfo = in.readBytes(length);
    153     }
    154 
    155 
    156 
    157     /** {@inheritDoc} */
    158     protected int placeItem(int offset) {
    159         offset += Leb128Utils.unsignedLeb128Size(lineStart);
    160         offset += Leb128Utils.unsignedLeb128Size(parameterNames.length);
    161         for (StringIdItem parameterName: parameterNames) {
    162             int indexp1;
    163             if (parameterName == null) {
    164                 indexp1 = 0;
    165             } else {
    166                 indexp1 = parameterName.getIndex() + 1;
    167             }
    168             offset += Leb128Utils.unsignedLeb128Size(indexp1);
    169         }
    170 
    171         //make a subclass so we can keep track of and access the computed length
    172         class ProcessDebugInstructionDelegateWithLength extends
    173                 DebugInstructionIterator.ProcessRawDebugInstructionDelegate {
    174             public int length = 0;
    175         }
    176         ProcessDebugInstructionDelegateWithLength pdidwl;
    177 
    178         //final referencedItems = this.referencedItems;
    179 
    180         DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo),
    181                 pdidwl = new ProcessDebugInstructionDelegateWithLength() {
    182                     private int referencedItemsPosition = 0;
    183 
    184                     @Override
    185                     public void ProcessStaticOpcode(DebugOpcode opcode, int startDebugOffset, int length) {
    186                         this.length+=length;
    187                     }
    188 
    189                     @Override
    190                     public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex,
    191                                                   int typeIndex, boolean registerIsSigned) {
    192                         this.length++;
    193                         if (dexFile.getPreserveSignedRegisters() && registerIsSigned) {
    194                             this.length += Leb128Utils.signedLeb128Size(registerNum);
    195                         } else {
    196                             this.length+=Leb128Utils.unsignedLeb128Size(registerNum);
    197                         }
    198                         if (nameIndex != -1) {
    199                             this.length+=
    200                                Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
    201                         } else {
    202                             this.length++;
    203                         }
    204                         if (typeIndex != -1) {
    205                             this.length+=
    206                                 Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
    207                         } else {
    208                             this.length++;
    209                         }
    210 
    211                     }
    212 
    213                     @Override
    214                     public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNum, int nameIndex,
    215                                                           int typeIndex, int signatureIndex,
    216                                                           boolean registerIsSigned) {
    217                         this.length++;
    218                         if (dexFile.getPreserveSignedRegisters() && registerIsSigned) {
    219                             this.length += Leb128Utils.signedLeb128Size(registerNum);
    220                         } else {
    221                             this.length+=Leb128Utils.unsignedLeb128Size(registerNum);
    222                         }
    223                         if (nameIndex != -1) {
    224                             this.length+=
    225                                Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
    226                         } else {
    227                             this.length++;
    228                         }
    229                         if (typeIndex != -1) {
    230                             this.length+=
    231                                Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
    232                         } else {
    233                             this.length++;
    234                         }
    235                         if (signatureIndex != -1) {
    236                             this.length+=
    237                                Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
    238                         } else {
    239                             this.length++;
    240                         }
    241                     }
    242 
    243                     @Override
    244                     public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
    245                         this.length++;
    246                         if (nameIndex != -1) {
    247                             this.length+=
    248                                Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
    249                         } else {
    250                             this.length++;
    251                         }
    252                     }
    253                 });
    254         return offset + pdidwl.length;
    255     }
    256 
    257     /** {@inheritDoc} */
    258     protected void writeItem(final AnnotatedOutput out) {
    259         if (out.annotates()) {
    260             writeItemWithAnnotations(out);
    261         } else {
    262             writeItemWithNoAnnotations(out);
    263         }
    264     }
    265 
    266     /**
    267      * Replaces the encoded debug info for this DebugInfoItem. It is expected that the new debug info is compatible
    268      * with the existing information, i.e. lineStart, referencedItems, parameterNames
    269      * @param encodedDebugInfo the new encoded debug info
    270      */
    271     protected void setEncodedDebugInfo(byte[] encodedDebugInfo) {
    272         //TODO: I would rather replace this method with some way of saying "The (code) instruction at address changed from A bytes to B bytes. Fixup the debug info accordingly"
    273 
    274         this.encodedDebugInfo = encodedDebugInfo;
    275     }
    276 
    277     /**
    278      * Helper method that writes the item, without writing annotations
    279      * @param out the AnnotatedOutput object
    280      */
    281     private void writeItemWithNoAnnotations(final AnnotatedOutput out) {
    282         out.writeUnsignedLeb128(lineStart);
    283         out.writeUnsignedLeb128(parameterNames.length);
    284         for (StringIdItem parameterName: parameterNames) {
    285             int indexp1;
    286             if (parameterName == null) {
    287                 indexp1 = 0;
    288             } else {
    289                 indexp1 = parameterName.getIndex() + 1;
    290             }
    291             out.writeUnsignedLeb128(indexp1);
    292         }
    293 
    294         DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo),
    295                 new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() {
    296                     private int referencedItemsPosition = 0;
    297 
    298                     @Override
    299                     public void ProcessStaticOpcode(DebugOpcode opcode, int startDebugOffset, int length) {
    300                         out.write(encodedDebugInfo, startDebugOffset, length);
    301                     }
    302 
    303                     @Override
    304                     public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex,
    305                                                   int typeIndex, boolean registerIsSigned) {
    306                         out.writeByte(DebugOpcode.DBG_START_LOCAL.value);
    307                         if (dexFile.getPreserveSignedRegisters() && registerIsSigned) {
    308                             out.writeSignedLeb128(registerNum);
    309                         } else {
    310                             out.writeUnsignedLeb128(registerNum);
    311                         }
    312                         if (nameIndex != -1) {
    313                             out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
    314                         } else {
    315                             out.writeByte(0);
    316                         }
    317                         if (typeIndex != -1) {
    318                             out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
    319                         } else {
    320                             out.writeByte(0);
    321                         }
    322                     }
    323 
    324                     @Override
    325                     public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNum, int nameIndex,
    326                                                           int typeIndex, int signatureIndex,
    327                                                           boolean registerIsSigned) {
    328                         out.writeByte(DebugOpcode.DBG_START_LOCAL_EXTENDED.value);
    329                         if (dexFile.getPreserveSignedRegisters() && registerIsSigned) {
    330                             out.writeSignedLeb128(registerNum);
    331                         } else {
    332                             out.writeUnsignedLeb128(registerNum);
    333                         }
    334                         if (nameIndex != -1) {
    335                             out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
    336                         } else {
    337                             out.writeByte(0);
    338                         }
    339                         if (typeIndex != -1) {
    340                             out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
    341                         } else {
    342                             out.writeByte(0);
    343                         }
    344                         if (signatureIndex != -1) {
    345                             out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
    346                         } else {
    347                             out.writeByte(0);
    348                         }
    349                     }
    350 
    351                     @Override
    352                     public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
    353                         out.writeByte(DebugOpcode.DBG_SET_FILE.value);
    354                         if (nameIndex != -1) {
    355                             out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
    356                         } else {
    357                             out.writeByte(0);
    358                         }
    359                     }
    360                 });
    361     }
    362 
    363     /**
    364      * Helper method that writes and annotates the item
    365      * @param out the AnnotatedOutput object
    366      */
    367     private void writeItemWithAnnotations(final AnnotatedOutput out) {
    368         out.annotate(0, parent.getParent().method.getMethodString());
    369         out.annotate("line_start: 0x" + Integer.toHexString(lineStart) + " (" + lineStart + ")");
    370         out.writeUnsignedLeb128(lineStart);
    371         out.annotate("parameters_size: 0x" + Integer.toHexString(parameterNames.length) + " (" + parameterNames.length
    372                 + ")");
    373         out.writeUnsignedLeb128(parameterNames.length);
    374         int index = 0;
    375         for (StringIdItem parameterName: parameterNames) {
    376             int indexp1;
    377             if (parameterName == null) {
    378                 out.annotate("[" + index++ +"] parameterName: ");
    379                 indexp1 = 0;
    380             } else {
    381                 out.annotate("[" + index++ +"] parameterName: " + parameterName.getStringValue());
    382                 indexp1 = parameterName.getIndex() + 1;
    383             }
    384             out.writeUnsignedLeb128(indexp1);
    385         }
    386 
    387         DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo),
    388                 new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() {
    389                     private int referencedItemsPosition = 0;
    390 
    391                     @Override
    392                     public void ProcessEndSequence(int startDebugOffset) {
    393                         out.annotate("DBG_END_SEQUENCE");
    394                         out.writeByte(DebugOpcode.DBG_END_SEQUENCE.value);
    395                     }
    396 
    397                     @Override
    398                     public void ProcessAdvancePC(int startDebugOffset, int length, int addressDiff) {
    399                         out.annotate("DBG_ADVANCE_PC");
    400                         out.writeByte(DebugOpcode.DBG_ADVANCE_PC.value);
    401                         out.indent();
    402                         out.annotate("addr_diff: 0x" + Integer.toHexString(addressDiff) + " (" + addressDiff + ")");
    403                         out.writeUnsignedLeb128(addressDiff);
    404                         out.deindent();
    405                     }
    406 
    407                     @Override
    408                     public void ProcessAdvanceLine(int startDebugOffset, int length, int lineDiff) {
    409                         out.annotate("DBG_ADVANCE_LINE");
    410                         out.writeByte(DebugOpcode.DBG_ADVANCE_LINE.value);
    411                         out.indent();
    412                         out.annotate("line_diff: 0x" + Integer.toHexString(lineDiff) + " (" + lineDiff + ")");
    413                         out.writeSignedLeb128(lineDiff);
    414                         out.deindent();
    415                     }
    416 
    417                     @Override
    418                     public void ProcessStartLocal(int startDebugOffset, int length, int registerNum, int nameIndex,
    419                                                   int typeIndex, boolean registerIsSigned) {
    420                         out.annotate("DBG_START_LOCAL");
    421                         out.writeByte(DebugOpcode.DBG_START_LOCAL.value);
    422                         out.indent();
    423                         out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")");
    424                         if (dexFile.getPreserveSignedRegisters() && registerIsSigned) {
    425                             out.writeSignedLeb128(registerNum);
    426                         } else {
    427                             out.writeUnsignedLeb128(registerNum);
    428                         }
    429                         if (nameIndex != -1) {
    430                             Item nameItem = referencedItems[referencedItemsPosition++];
    431                             assert nameItem instanceof StringIdItem;
    432                             out.annotate("name: " + ((StringIdItem)nameItem).getStringValue());
    433                             out.writeUnsignedLeb128(nameItem.getIndex() + 1);
    434                         } else {
    435                             out.annotate("name: ");
    436                             out.writeByte(0);
    437                         }
    438                         if (typeIndex != -1) {
    439                             Item typeItem = referencedItems[referencedItemsPosition++];
    440                             assert typeItem instanceof TypeIdItem;
    441                             out.annotate("type: " + ((TypeIdItem)typeItem).getTypeDescriptor());
    442                             out.writeUnsignedLeb128(typeItem.getIndex() + 1);
    443                         } else {
    444                             out.annotate("type: ");
    445                             out.writeByte(0);
    446                         }
    447                         out.deindent();
    448                     }
    449 
    450                     @Override
    451                     public void ProcessStartLocalExtended(int startDebugOffset, int length, int registerNum,
    452                                                           int nameIndex, int typeIndex, int signatureIndex,
    453                                                           boolean registerIsSigned) {
    454                         out.annotate("DBG_START_LOCAL_EXTENDED");
    455                         out.writeByte(DebugOpcode.DBG_START_LOCAL_EXTENDED.value);
    456                         out.indent();
    457                         out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")");
    458                         if (dexFile.getPreserveSignedRegisters() && registerIsSigned) {
    459                             out.writeSignedLeb128(registerNum);
    460                         } else {
    461                             out.writeUnsignedLeb128(registerNum);
    462                         }
    463                         if (nameIndex != -1) {
    464                             Item nameItem = referencedItems[referencedItemsPosition++];
    465                             assert nameItem instanceof StringIdItem;
    466                             out.annotate("name: " + ((StringIdItem)nameItem).getStringValue());
    467                             out.writeUnsignedLeb128(nameItem.getIndex() + 1);
    468                         } else {
    469                             out.annotate("name: ");
    470                             out.writeByte(0);
    471                         }
    472                         if (typeIndex != -1) {
    473                             Item typeItem = referencedItems[referencedItemsPosition++];
    474                             assert typeItem instanceof TypeIdItem;
    475                             out.annotate("type: " + ((TypeIdItem)typeItem).getTypeDescriptor());
    476                             out.writeUnsignedLeb128(typeItem.getIndex() + 1);
    477                         } else {
    478                             out.annotate("type: ");
    479                             out.writeByte(0);
    480                         }
    481                         if (signatureIndex != -1) {
    482                             Item signatureItem = referencedItems[referencedItemsPosition++];
    483                             assert signatureItem instanceof StringIdItem;
    484                             out.annotate("signature: " + ((StringIdItem)signatureItem).getStringValue());
    485                             out.writeUnsignedLeb128(signatureItem.getIndex() + 1);
    486                         } else {
    487                             out.annotate("signature: ");
    488                             out.writeByte(0);
    489                         }
    490                         out.deindent();
    491                     }
    492 
    493                     @Override
    494                     public void ProcessEndLocal(int startDebugOffset, int length, int registerNum,
    495                                                 boolean registerIsSigned) {
    496                         out.annotate("DBG_END_LOCAL");
    497                         out.writeByte(DebugOpcode.DBG_END_LOCAL.value);
    498                         out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")");
    499                         if (registerIsSigned) {
    500                             out.writeSignedLeb128(registerNum);
    501                         } else {
    502                             out.writeUnsignedLeb128(registerNum);
    503                         }
    504                     }
    505 
    506                     @Override
    507                     public void ProcessRestartLocal(int startDebugOffset, int length, int registerNum,
    508                                                     boolean registerIsSigned) {
    509                         out.annotate("DBG_RESTART_LOCAL");
    510                         out.writeByte(DebugOpcode.DBG_RESTART_LOCAL.value);
    511                         out.annotate("register_num: 0x" + Integer.toHexString(registerNum) + " (" + registerNum + ")");
    512                         if (registerIsSigned) {
    513                             out.writeSignedLeb128(registerNum);
    514                         } else {
    515                             out.writeUnsignedLeb128(registerNum);
    516                         }
    517                     }
    518 
    519                     @Override
    520                     public void ProcessSetPrologueEnd(int startDebugOffset) {
    521                         out.annotate("DBG_SET_PROLOGUE_END");
    522                         out.writeByte(DebugOpcode.DBG_SET_PROLOGUE_END.value);
    523                     }
    524 
    525                     @Override
    526                     public void ProcessSetEpilogueBegin(int startDebugOffset) {
    527                         out.annotate("DBG_SET_EPILOGUE_BEGIN");
    528                         out.writeByte(DebugOpcode.DBG_SET_EPILOGUE_BEGIN.value);
    529                     }
    530 
    531                     @Override
    532                     public void ProcessSetFile(int startDebugOffset, int length, int nameIndex) {
    533                         out.annotate("DBG_SET_FILE");
    534                         out.writeByte(DebugOpcode.DBG_SET_FILE.value);
    535                         if (nameIndex != -1) {
    536                             Item sourceItem = referencedItems[referencedItemsPosition++];
    537                             assert sourceItem instanceof StringIdItem;
    538                             out.annotate("source_file: \"" + ((StringIdItem)sourceItem).getStringValue() + "\"");
    539                             out.writeUnsignedLeb128(sourceItem.getIndex() + 1);
    540                         } else {
    541                             out.annotate("source_file: ");
    542                             out.writeByte(0);
    543                         }
    544                     }
    545 
    546                     @Override
    547                     public void ProcessSpecialOpcode(int startDebugOffset, int debugOpcode, int lineDiff,
    548                                                      int addressDiff) {
    549                         out.annotate("DBG_SPECIAL_OPCODE: line_diff=0x" + Integer.toHexString(lineDiff) + "(" +
    550                                 lineDiff +"),addressDiff=0x" + Integer.toHexString(addressDiff) + "(" + addressDiff +
    551                                 ")");
    552                         out.writeByte(debugOpcode);
    553                     }
    554                 });
    555     }
    556 
    557 
    558 
    559 
    560     /** {@inheritDoc} */
    561     public ItemType getItemType() {
    562         return ItemType.TYPE_DEBUG_INFO_ITEM;
    563     }
    564 
    565     /** {@inheritDoc} */
    566     public String getConciseIdentity() {
    567         return "debug_info_item @0x" + Integer.toHexString(getOffset());
    568     }
    569 
    570     /** {@inheritDoc} */
    571     public int compareTo(DebugInfoItem other) {
    572         if (parent == null) {
    573             if (other.parent == null) {
    574                 return 0;
    575             }
    576             return -1;
    577         }
    578         if (other.parent == null) {
    579             return 1;
    580         }
    581         return parent.compareTo(other.parent);
    582     }
    583 
    584     /**
    585      * Set the <code>CodeItem</code> that this <code>DebugInfoItem</code> is associated with
    586      * @param codeItem the <code>CodeItem</code> that this <code>DebugInfoItem</code> is associated with
    587      */
    588     protected void setParent(CodeItem codeItem) {
    589         this.parent = codeItem;
    590     }
    591 
    592     /**
    593      * @return the initial value for the line number register for the debug info machine
    594      */
    595     public int getLineStart() {
    596         return lineStart;
    597     }
    598 
    599     /**
    600      * @return the debug info, encoded as a byte array
    601      */
    602     public byte[] getEncodedDebugInfo() {
    603         return encodedDebugInfo;
    604     }
    605 
    606     /**
    607      * @return an array of the items referenced by instructions, in order of occurance in the encoded debug info
    608      */
    609     public Item[] getReferencedItems() {
    610         return referencedItems;
    611     }
    612 
    613     /**
    614      * @return an array of the names of the associated method's parameters. The array can be null if no parameter info
    615      * is available, or any element can be null to indicate no info for that parameter
    616      */
    617     public StringIdItem[] getParameterNames() {
    618         return parameterNames;
    619     }
    620 }
    621