MethodDefinition.java revision ff80035f438dd2a70330931bb87e37bb8b42f9e0
1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2009 Ben Gruver
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.baksmali.Adaptors;
30
31import org.jf.baksmali.Adaptors.Format.*;
32import org.jf.baksmali.baksmali;
33import org.jf.dexlib.*;
34import org.jf.dexlib.Debug.DebugInstructionIterator;
35import org.jf.dexlib.Code.Format.*;
36import org.jf.dexlib.Code.Instruction;
37import org.jf.dexlib.Code.Opcode;
38import org.jf.dexlib.Code.InstructionIterator;
39import org.jf.dexlib.Util.AccessFlags;
40import org.antlr.stringtemplate.StringTemplateGroup;
41import org.antlr.stringtemplate.StringTemplate;
42
43import java.util.*;
44
45public class MethodDefinition {
46    public static StringTemplate makeTemplate(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod,
47                                              AnnotationSetItem annotationSet,
48                                              AnnotationSetRefList parameterAnnotations) {
49
50        CodeItem codeItem = encodedMethod.codeItem;
51
52        int temp = encodedMethod.method.getPrototype().getParameterRegisterCount();
53
54        StringTemplate template = stg.getInstanceOf("method");
55
56        template.setAttribute("AccessFlags", getAccessFlags(encodedMethod));
57        template.setAttribute("MethodName", encodedMethod.method.getMethodName().getStringValue());
58        template.setAttribute("Prototype", encodedMethod.method.getPrototype().getPrototypeString());
59        template.setAttribute("HasCode", codeItem != null);
60        template.setAttribute("RegistersDirective", baksmali.useLocalsDirective?".locals":".registers");
61        template.setAttribute("RegisterCount", codeItem==null?"0":Integer.toString(getRegisterCount(encodedMethod)));
62        template.setAttribute("Parameters", getParameters(stg, codeItem, parameterAnnotations));
63        template.setAttribute("Annotations", getAnnotations(stg, annotationSet));
64        template.setAttribute("MethodItems", getMethodItems(encodedMethod.method.getDexFile(), stg, codeItem));
65
66        return template;
67    }
68
69    private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod)
70    {
71        int totalRegisters = encodedMethod.codeItem.getRegisterCount();
72        if (baksmali.useLocalsDirective) {
73            int parameterRegisters = encodedMethod.method.getPrototype().getParameterRegisterCount();
74            if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
75                parameterRegisters++;
76            }
77            return totalRegisters - parameterRegisters;
78        }
79        return totalRegisters;
80    }
81
82    private static List<String> getAccessFlags(ClassDataItem.EncodedMethod encodedMethod) {
83        List<String> accessFlags = new ArrayList<String>();
84
85        for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) {
86            accessFlags.add(accessFlag.toString());
87        }
88
89        return accessFlags;
90    }
91
92    private static List<StringTemplate> getParameters(StringTemplateGroup stg, CodeItem codeItem,
93                                                               AnnotationSetRefList parameterAnnotations) {
94        DebugInfoItem debugInfoItem = null;
95        if (codeItem != null) {
96            debugInfoItem = codeItem.getDebugInfo();
97        }
98
99        int parameterCount = 0;
100
101        List<AnnotationSetItem> annotations = new ArrayList<AnnotationSetItem>();
102        if (parameterAnnotations != null) {
103            AnnotationSetItem[] _annotations = parameterAnnotations.getAnnotationSets();
104            if (_annotations != null) {
105                annotations.addAll(Arrays.asList(_annotations));
106            }
107
108            parameterCount = annotations.size();
109        }
110
111        List<String> parameterNames = new ArrayList<String>();
112        if (debugInfoItem != null) {
113            StringIdItem[] _parameterNames = debugInfoItem.getParameterNames();
114            if (_parameterNames != null) {
115                for (StringIdItem parameterName: _parameterNames) {
116                    parameterNames.add(parameterName==null?null:parameterName.getStringValue());
117                }
118            }
119
120            if (parameterCount < parameterNames.size()) {
121                parameterCount = parameterNames.size();
122            }
123        }
124
125        List<StringTemplate> parameters = new ArrayList<StringTemplate>();
126        for (int i=0; i<parameterCount; i++) {
127            AnnotationSetItem annotationSet = null;
128            if (i < annotations.size()) {
129                annotationSet = annotations.get(i);
130            }
131
132            String parameterName = null;
133            if (i < parameterNames.size()) {
134                parameterName = parameterNames.get(i);
135            }
136
137            parameters.add(ParameterAdaptor.makeTemplate(stg, parameterName, annotationSet));
138        }
139
140        return parameters;
141    }
142
143    private static List<StringTemplate> getAnnotations(StringTemplateGroup stg, AnnotationSetItem annotationSet) {
144        if (annotationSet == null) {
145            return null;
146        }
147
148        List<StringTemplate> annotationAdaptors = new ArrayList<StringTemplate>();
149
150        for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
151            annotationAdaptors.add(AnnotationAdaptor.makeTemplate(stg, annotationItem));
152        }
153        return annotationAdaptors;
154    }
155
156    private static List<MethodItem> getMethodItems(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) {
157        List<MethodItem> methodItems = new ArrayList<MethodItem>();
158
159        MethodItemList methodItemList = new MethodItemList(dexFile, stg, codeItem);
160        methodItemList.generateMethodItemList();
161
162        methodItems.addAll(methodItemList.labels.values());
163        methodItems.addAll(methodItemList.instructions);
164        methodItems.addAll(methodItemList.blanks);
165        methodItems.addAll(methodItemList.catches);
166        methodItems.addAll(methodItemList.debugItems);
167        Collections.sort(methodItems);
168
169        return methodItems;
170    }
171
172
173    private static class MethodItemList {
174        private final DexFile dexFile;
175        private final StringTemplateGroup stg;
176        private final CodeItem codeItem;
177
178        public HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>();
179        public List<MethodItem> instructions = new ArrayList<MethodItem>();
180        public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>();
181        public List<CatchMethodItem> catches = new ArrayList<CatchMethodItem>();
182        public List<MethodItem> debugItems = new ArrayList<MethodItem>();
183
184        private HashMap<Integer, Integer> packedSwitchMap = new HashMap<Integer, Integer>();
185        private HashMap<Integer, Integer> sparseSwitchMap = new HashMap<Integer, Integer>();
186
187        public MethodItemList(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) {
188            this.dexFile = dexFile;
189            this.stg = stg;
190            this.codeItem = codeItem;
191        }
192
193        public void generateMethodItemList() {
194            if (codeItem == null) {
195                return;
196            }
197
198            if (baksmali.deodexUtil != null && dexFile.isOdex()) {
199                List<Instruction> instructions = baksmali.deodexUtil.deodexerizeCode(codeItem);
200
201                int offset = 0;
202                for (Instruction instruction: instructions) {
203                    if (instruction.opcode == Opcode.PACKED_SWITCH) {
204                        Instruction31t ins = (Instruction31t)instruction;
205                        packedSwitchMap.put(offset + ins.getOffset(), offset);
206                    } else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
207                        Instruction31t ins = (Instruction31t)instruction;
208                        sparseSwitchMap.put(offset + ins.getOffset(), offset);
209                    }
210
211                    offset += instruction.getSize()/2;
212                }
213
214                offset = 0;
215                for (Instruction instruction: instructions) {
216                    addMethodItemsForInstruction(offset, instruction, false, null);
217                    blanks.add(new BlankMethodItem(stg, offset));
218
219                    offset += instruction.getSize()/2;
220                }
221            } else {
222                final byte[] encodedInstructions = codeItem.getEncodedInstructions();
223
224                InstructionIterator.IterateInstructions(encodedInstructions,
225                        new InstructionIterator.ProcessRawInstructionDelegate() {
226                            public void ProcessNormalInstruction(Opcode opcode, int index) {
227                                if (opcode == Opcode.PACKED_SWITCH) {
228                                    Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction(
229                                            dexFile, opcode, encodedInstructions, index);
230                                    packedSwitchMap.put(index/2 + ins.getOffset(), index/2);
231                                } else if (opcode == Opcode.SPARSE_SWITCH) {
232                                    Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction(
233                                            dexFile, opcode, encodedInstructions, index);
234                                    sparseSwitchMap.put(index/2 + ins.getOffset(),  index/2);
235                                }
236                            }
237
238                            public void ProcessReferenceInstruction(Opcode opcode, int index) {
239                            }
240
241                            public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) {
242                            }
243
244                            public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) {
245                            }
246
247                            public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount,
248                                                                        int instructionLength) {
249                            }
250                        });
251
252                InstructionIterator.IterateInstructions(dexFile, encodedInstructions,
253                        new InstructionIterator.ProcessInstructionDelegate() {
254                            public void ProcessInstruction(int index, Instruction instruction) {
255                                int offset = index/2;
256                                addMethodItemsForInstruction(offset, instruction, false, null);
257                                blanks.add(new BlankMethodItem(stg, offset));
258                            }
259                        });
260            }
261
262            blanks.remove(blanks.size()-1);
263
264            addTries();
265
266            addDebugInfo();
267        }
268
269        private void addInstructionMethodItem(InstructionFormatMethodItem methodItem, boolean commentedOut,
270                                              String comment) {
271            if (commentedOut) {
272                instructions.add(new CommentedOutMethodItem(stg, methodItem));
273            } else {
274                instructions.add(methodItem);
275            }
276        }
277
278        private void addLabelMethodItem(LabelMethodItem labelMethodItem) {
279            LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem);
280            if (internedLabelMethodItem != null) {
281                if (!labelMethodItem.isCommentedOut() && internedLabelMethodItem.isCommentedOut()) {
282                    internedLabelMethodItem.setCommentedOut(false);
283                }
284            } else {
285                labels.put(labelMethodItem, labelMethodItem);
286            }
287        }
288
289        private void addMethodItemsForInstruction(int offset, Instruction instruction, boolean commentedOut,
290                                                  String comment) {
291            switch (instruction.getFormat()) {
292                case Format10t:
293                    addInstructionMethodItem(
294                            new Instruction10tMethodItem(codeItem, offset, stg,(Instruction10t)instruction),
295                            commentedOut, comment);
296                    addLabelMethodItem(new LabelMethodItem(offset + ((Instruction10t)instruction).getOffset(), stg,
297                            "goto_", commentedOut));
298                    return;
299                case Format10x:
300                    addInstructionMethodItem(
301                            new Instruction10xMethodItem(codeItem, offset, stg, (Instruction10x)instruction),
302                            commentedOut, comment);
303                    return;
304                case Format11n:
305                    addInstructionMethodItem(
306                            new Instruction11nMethodItem(codeItem, offset, stg, (Instruction11n)instruction),
307                            commentedOut, comment);
308                    return;
309                case Format11x:
310                    addInstructionMethodItem(
311                            new Instruction11xMethodItem(codeItem, offset, stg, (Instruction11x)instruction),
312                            commentedOut, comment);
313                    return;
314                case Format12x:
315                    addInstructionMethodItem(
316                            new Instruction12xMethodItem(codeItem, offset, stg, (Instruction12x)instruction),
317                            commentedOut, comment);
318                    return;
319                case Format20t:
320                    addInstructionMethodItem(
321                            new Instruction20tMethodItem(codeItem, offset, stg, (Instruction20t)instruction),
322                            commentedOut, comment);
323                    addLabelMethodItem(new LabelMethodItem(offset + ((Instruction20t)instruction).getOffset(), stg,
324                            "goto_", commentedOut));
325                    return;
326                case Format21c:
327                    addInstructionMethodItem(
328                            new Instruction21cMethodItem(codeItem, offset, stg, (Instruction21c)instruction),
329                            commentedOut, comment);
330                    return;
331                case Format21h:
332                    addInstructionMethodItem(
333                            new Instruction21hMethodItem(codeItem, offset, stg, (Instruction21h)instruction),
334                            commentedOut, comment);
335                    return;
336                case Format21s:
337                    addInstructionMethodItem(
338                            new Instruction21sMethodItem(codeItem, offset, stg, (Instruction21s)instruction),
339                            commentedOut, comment);
340                    return;
341                case Format21t:
342                    addInstructionMethodItem(
343                            new Instruction21tMethodItem(codeItem, offset, stg, (Instruction21t)instruction),
344                            commentedOut, comment);
345                    addLabelMethodItem(new LabelMethodItem(offset + ((Instruction21t)instruction).getOffset(), stg,
346                            "cond_", commentedOut));
347                    return;
348                case Format22b:
349                    addInstructionMethodItem(
350                            new Instruction22bMethodItem(codeItem, offset, stg, (Instruction22b)instruction),
351                            commentedOut, comment);
352                    return;
353                case Format22c:
354                    addInstructionMethodItem(
355                            new Instruction22cMethodItem(codeItem, offset, stg, (Instruction22c)instruction),
356                            commentedOut, comment);
357                    return;
358                case Format22cs:
359                    addInstructionMethodItem(
360                            new Instruction22csMethodItem(codeItem, offset, stg, (Instruction22cs)instruction),
361                            commentedOut, comment);
362                    return;
363                case Format22csf:
364                    addInstructionMethodItem(
365                            new Instruction22csfMethodItem(codeItem, offset, stg, (Instruction22csf)instruction),
366                            commentedOut, comment);
367                    return;
368                case Format22s:
369                    addInstructionMethodItem(
370                            new Instruction22sMethodItem(codeItem, offset, stg, (Instruction22s)instruction),
371                            commentedOut, comment);
372                    return;
373                case Format22t:
374                    addInstructionMethodItem(
375                            new Instruction22tMethodItem(codeItem, offset, stg, (Instruction22t)instruction),
376                            commentedOut, comment);
377                    addLabelMethodItem(new LabelMethodItem(offset + ((Instruction22t)instruction).getOffset(), stg,
378                            "cond_", commentedOut));
379                    return;
380                case Format22x:
381                    addInstructionMethodItem(
382                            new Instruction22xMethodItem(codeItem, offset, stg, (Instruction22x)instruction),
383                            commentedOut, comment);
384                    return;
385                case Format23x:
386                    addInstructionMethodItem(
387                            new Instruction23xMethodItem(codeItem, offset, stg, (Instruction23x)instruction),
388                            commentedOut, comment);
389                    return;
390                case Format30t:
391                    addInstructionMethodItem(
392                            new Instruction30tMethodItem(codeItem, offset, stg, (Instruction30t)instruction),
393                            commentedOut, comment);
394                    addLabelMethodItem(new LabelMethodItem(offset + ((Instruction30t)instruction).getOffset(), stg,
395                            "goto_", commentedOut));
396                    return;
397                case Format31c:
398                    addInstructionMethodItem(
399                            new Instruction31cMethodItem(codeItem, offset, stg, (Instruction31c)instruction),
400                            commentedOut, comment);
401                    return;
402                case Format31i:
403                    addInstructionMethodItem(
404                            new Instruction31iMethodItem(codeItem, offset, stg, (Instruction31i)instruction),
405                            commentedOut, comment);
406                    return;
407                case Format31t:
408                    addInstructionMethodItem(
409                            new Instruction31tMethodItem(codeItem, offset, stg, (Instruction31t)instruction),
410                            commentedOut, comment);
411                    if (instruction.opcode == Opcode.FILL_ARRAY_DATA) {
412                        addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
413                                "array_", commentedOut));
414                    } else if (instruction.opcode == Opcode.PACKED_SWITCH) {
415                        addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
416                                "pswitch_data_", commentedOut));
417                    } else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
418                        addLabelMethodItem(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
419                                "sswitch_data_", commentedOut));
420                    }
421                    return;
422                case Format32x:
423                    addInstructionMethodItem(
424                            new Instruction32xMethodItem(codeItem, offset, stg, (Instruction32x)instruction),
425                            commentedOut, comment);
426                    return;
427                case Format35c:
428                    addInstructionMethodItem(
429                            new Instruction35cMethodItem(codeItem, offset, stg, (Instruction35c)instruction),
430                            commentedOut, comment);
431                    return;
432                case Format35s:
433                    addInstructionMethodItem(
434                            new Instruction35sMethodItem(codeItem, offset, stg, (Instruction35s)instruction),
435                            commentedOut, comment);
436                    return;
437                case Format35sf:
438                    addInstructionMethodItem(
439                            new Instruction35sfMethodItem(codeItem, offset, stg, (Instruction35sf)instruction),
440                            commentedOut, comment);
441                    return;
442                case Format35ms:
443                    addInstructionMethodItem(
444                            new Instruction35msMethodItem(codeItem, offset, stg, (Instruction35ms)instruction),
445                            commentedOut, comment);
446                    return;
447                case Format35msf:
448                    addInstructionMethodItem(
449                            new Instruction35msfMethodItem(codeItem, offset, stg, (Instruction35msf)instruction),
450                            commentedOut, comment);
451                    return;
452                case Format3rc:
453                    addInstructionMethodItem(
454                            new Instruction3rcMethodItem(codeItem, offset, stg, (Instruction3rc)instruction),
455                            commentedOut, comment);
456                    return;
457                case Format3rms:
458                    addInstructionMethodItem(
459                            new Instruction3rmsMethodItem(codeItem, offset, stg, (Instruction3rms)instruction),
460                            commentedOut, comment);
461                    return;
462                case Format3rmsf:
463                    addInstructionMethodItem(
464                            new Instruction3rmsfMethodItem(codeItem, offset, stg, (Instruction3rmsf)instruction),
465                            commentedOut, comment);
466                    return;
467                case Format51l:
468                    addInstructionMethodItem(
469                            new Instruction51lMethodItem(codeItem, offset, stg, (Instruction51l)instruction),
470                            commentedOut, comment);
471                    return;
472                case ArrayData:
473                    addInstructionMethodItem(
474                            new ArrayDataMethodItem(codeItem, offset, stg, (ArrayDataPseudoInstruction)instruction),
475                            commentedOut, comment);
476                    return;
477                case PackedSwitchData:
478                {
479                    final Integer baseAddress = packedSwitchMap.get(offset);
480
481                    if (baseAddress != null) {
482                        PackedSwitchDataPseudoInstruction packedSwitchInstruction =
483                                (PackedSwitchDataPseudoInstruction)instruction;
484
485                        addInstructionMethodItem(
486                                new PackedSwitchMethodItem(codeItem, offset, stg, packedSwitchInstruction, baseAddress),
487                            commentedOut, comment);
488
489                        Iterator<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> iterator =
490                                packedSwitchInstruction.getTargets();
491                        while (iterator.hasNext()) {
492                            PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
493                            addLabelMethodItem(new LabelMethodItem(baseAddress + target.target, stg, "pswitch_",
494                                    commentedOut));
495                        }
496                    }
497                    return;
498                }
499                case SparseSwitchData:
500                {
501                    final Integer baseAddress = sparseSwitchMap.get(offset);
502
503                    if (baseAddress != null) {
504                        SparseSwitchDataPseudoInstruction sparseSwitchInstruction =
505                                (SparseSwitchDataPseudoInstruction)instruction;
506
507                        addInstructionMethodItem(
508                                new SparseSwitchMethodItem(codeItem, offset, stg, sparseSwitchInstruction, baseAddress),
509                            commentedOut, comment);
510
511                        Iterator<SparseSwitchDataPseudoInstruction.SparseSwitchTarget> iterator =
512                                sparseSwitchInstruction.getTargets();
513                        while (iterator.hasNext()) {
514                            SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next();
515                            addLabelMethodItem(new LabelMethodItem(baseAddress + target.target, stg, "sswitch_",
516                                    commentedOut));
517                        }
518                    }
519                    return;
520                }
521                case UnresolvedNullReference:
522                {
523                    addInstructionMethodItem(new UnresolvedNullReferenceMethodItem(codeItem, offset, stg,
524                            (UnresolvedNullReference)instruction), commentedOut, comment);
525                    addMethodItemsForInstruction(offset, ((UnresolvedNullReference)instruction).OriginalInstruction,
526                            true, null);
527                    return;
528                }
529                case DeadInstruction:
530                {
531                    //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
532                    addMethodItemsForInstruction(offset, ((DeadInstruction)instruction).OriginalInstruction, true, null);
533                    return;
534                }
535            }
536        }
537
538        private void addTries() {
539            if (codeItem.getTries() == null) {
540                return;
541            }
542            for (CodeItem.TryItem tryItem: codeItem.getTries()) {
543                int startAddress = tryItem.startAddress;
544                int endAddress = tryItem.startAddress + tryItem.instructionCount;
545
546                /**
547                 * The end address points to the address immediately after the end of the last
548                 * instruction that the try block covers. We want the .catch directive and end_try
549                 * label to be associated with the last covered instruction, so we need to get
550                 * the offset for that instruction
551                 */
552                int index = Collections.binarySearch(instructions, new BlankMethodItem(stg, endAddress));
553                if (index < 0) {
554                    index = (index * -1) - 1;
555                }
556                //index should never by 0, so this should be safe
557                if (index == instructions.size()) {
558                    //if the end address is the same as the address of the last instruction, then
559                    //this try item ends at the next to last instruction.
560                    //otherwise, if the end address is past the address of the last instruction,
561                    //thin this try item ends at the last instruction
562                    if (instructions.get(instructions.size() - 1).getOffset() == endAddress) {
563                        //get the address for the next to last instruction
564                        index -= 2;
565                    } else {
566                        //get the address for the last instruction
567                        index--;
568                    }
569                } else {
570                    index -= 2;
571                }
572
573                int lastInstructionOffset = instructions.get(index).getOffset();
574
575                //add the catch all handler if it exists
576                int catchAllAddress = tryItem.encodedCatchHandler.catchAllHandlerAddress;
577                if (catchAllAddress != -1) {
578                    CatchMethodItem catchMethodItem = new CatchMethodItem(lastInstructionOffset, stg, null,
579                            startAddress, endAddress, catchAllAddress) {
580                        public String getTemplateName() {
581                            return "CatchAll";
582                        }
583                    };
584                    catches.add(catchMethodItem);
585
586                    addLabelMethodItem(new LabelMethodItem(startAddress, stg, "try_start_", false));
587                    //use the offset from the last covered instruction, but make the label
588                    //name refer to the address of the next instruction
589                    addLabelMethodItem(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress));
590                    addLabelMethodItem(new LabelMethodItem(catchAllAddress, stg, "handler_", false));
591
592                }
593
594                //add the rest of the handlers
595                //TODO: find adjacent handlers for the same type and combine them
596                for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
597                    //use the offset from the last covered instruction
598                    CatchMethodItem catchMethodItem = new CatchMethodItem(lastInstructionOffset, stg,
599                            handler.exceptionType, startAddress, endAddress, handler.handlerAddress);
600                    catches.add(catchMethodItem);
601
602                    addLabelMethodItem(new LabelMethodItem(startAddress, stg, "try_start_", false));
603                    //use the offset from the last covered instruction, but make the label
604                    //name refer to the address of the next instruction
605                    addLabelMethodItem(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress));
606                    addLabelMethodItem(new LabelMethodItem(handler.handlerAddress, stg, "handler_", false));
607                }
608            }
609        }
610
611        private void addDebugInfo() {
612            DebugInfoItem debugInfoItem = codeItem.getDebugInfo();
613            if (debugInfoItem == null) {
614                return;
615            }
616
617            DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(),
618                    new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() {
619                        @Override
620                        public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
621                                                      TypeIdItem type) {
622                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", -1,
623                                    registerNum, name, type, null));
624                        }
625
626                        @Override
627                        public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum,
628                                                              StringIdItem name, TypeIdItem type,
629                                                              StringIdItem signature) {
630                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", -1,
631                                    registerNum, name, type, signature));
632                        }
633
634                        @Override
635                        public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name,
636                                                    TypeIdItem type, StringIdItem signature) {
637                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "EndLocal", -1,
638                                    registerNum, name, type, signature));
639                        }
640
641                        @Override
642                        public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
643                                                        TypeIdItem type, StringIdItem signature) {
644                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "RestartLocal", -1,
645                                    registerNum, name, type, signature));
646                        }
647
648                        @Override
649                        public void ProcessSetPrologueEnd(int codeAddress) {
650                            debugItems.add(new DebugMethodItem(codeAddress, stg, "EndPrologue", -4));
651                        }
652
653                        @Override
654                        public void ProcessSetEpilogueBegin(int codeAddress) {
655                            debugItems.add(new DebugMethodItem(codeAddress, stg, "StartEpilogue", -4));
656                        }
657
658                        @Override
659                        public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) {
660                            debugItems.add(new DebugMethodItem(codeAddress, stg, "SetFile", -3) {
661                                @Override
662                                protected void setAttributes(StringTemplate template) {
663                                    template.setAttribute("FileName", name.getStringValue());
664                                }
665                            });
666                        }
667
668                        @Override
669                        public void ProcessLineEmit(int codeAddress, final int line) {
670                             debugItems.add(new DebugMethodItem(codeAddress, stg, "Line", -2) {
671                                 @Override
672                                 protected void setAttributes(StringTemplate template) {
673                                     template.setAttribute("Line", line);
674                                 }
675                             });
676                        }
677                    });
678        }
679    }
680}
681