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
29package org.jf.dexlib;
30
31import org.jf.dexlib.Debug.DebugInstructionIterator;
32import org.jf.dexlib.Debug.DebugOpcode;
33import org.jf.dexlib.Util.AnnotatedOutput;
34import org.jf.dexlib.Util.ByteArrayInput;
35import org.jf.dexlib.Util.Input;
36import org.jf.dexlib.Util.Leb128Utils;
37
38import java.util.ArrayList;
39import java.util.List;
40
41public 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