MethodDefinition.java revision 7ab77bc90be62b0688c97d4476e3bd219eace0da
1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/*
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * [The "BSD licence"]
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright (c) 2009 Ben Gruver
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * All rights reserved.
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Redistribution and use in source and binary forms, with or without
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * modification, are permitted provided that the following conditions
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * are met:
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 1. Redistributions of source code must retain the above copyright
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *    notice, this list of conditions and the following disclaimer.
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *    notice, this list of conditions and the following disclaimer in the
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *    documentation and/or other materials provided with the distribution.
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 3. The name of the author may not be used to endorse or promote products
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *    derived from this software without specific prior written permission.
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgpackage org.jf.baksmali.Adaptors;
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.jf.baksmali.Adaptors.Format.*;
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.jf.dexlib.*;
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.jf.dexlib.Debug.DebugInstructionIterator;
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.jf.dexlib.Code.Format.*;
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.jf.dexlib.Code.Instruction;
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.jf.dexlib.Code.Opcode;
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.jf.dexlib.Code.InstructionIterator;
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.jf.dexlib.Util.AccessFlags;
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.antlr.stringtemplate.StringTemplateGroup;
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport org.antlr.stringtemplate.StringTemplate;
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgimport java.util.*;
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgpublic class MethodDefinition {
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    public static StringTemplate makeTemplate(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod,
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                              AnnotationSetItem annotationSet,
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                              AnnotationSetRefList parameterAnnotations) {
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        CodeItem codeItem = encodedMethod.codeItem;
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        StringTemplate template = stg.getInstanceOf("method");
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        template.setAttribute("AccessFlags", getAccessFlags(encodedMethod));
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        template.setAttribute("MethodName", encodedMethod.method.getMethodName().getStringValue());
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        template.setAttribute("Prototype", encodedMethod.method.getPrototype().getPrototypeString());
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        template.setAttribute("HasCode", codeItem != null);
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        template.setAttribute("RegisterCount", codeItem==null?"0":Integer.toString(codeItem.getRegisterCount()));
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        template.setAttribute("Parameters", getParameters(stg, codeItem, parameterAnnotations));
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org        template.setAttribute("Annotations", getAnnotations(stg, annotationSet));
60        template.setAttribute("MethodItems", getMethodItems(encodedMethod.method.getDexFile(), stg, codeItem));
61
62        return template;
63    }
64
65    private static List<String> getAccessFlags(ClassDataItem.EncodedMethod encodedMethod) {
66        List<String> accessFlags = new ArrayList<String>();
67
68        for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) {
69            accessFlags.add(accessFlag.toString());
70        }
71
72        return accessFlags;
73    }
74
75    private static List<StringTemplate> getParameters(StringTemplateGroup stg, CodeItem codeItem,
76                                                               AnnotationSetRefList parameterAnnotations) {
77        DebugInfoItem debugInfoItem = null;
78        if (codeItem != null) {
79            debugInfoItem = codeItem.getDebugInfo();
80        }
81
82        int parameterCount = 0;
83
84        List<AnnotationSetItem> annotations = new ArrayList<AnnotationSetItem>();
85        if (parameterAnnotations != null) {
86            AnnotationSetItem[] _annotations = parameterAnnotations.getAnnotationSets();
87            if (_annotations != null) {
88                annotations.addAll(Arrays.asList(_annotations));
89            }
90
91            parameterCount = annotations.size();
92        }
93
94        List<String> parameterNames = new ArrayList<String>();
95        if (debugInfoItem != null) {
96            StringIdItem[] _parameterNames = debugInfoItem.getParameterNames();
97            if (_parameterNames != null) {
98                for (StringIdItem parameterName: _parameterNames) {
99                    parameterNames.add(parameterName==null?null:parameterName.getStringValue());
100                }
101            }
102
103            if (parameterCount < parameterNames.size()) {
104                parameterCount = parameterNames.size();
105            }
106        }
107
108        List<StringTemplate> parameters = new ArrayList<StringTemplate>();
109        for (int i=0; i<parameterCount; i++) {
110            AnnotationSetItem annotationSet = null;
111            if (i < annotations.size()) {
112                annotationSet = annotations.get(i);
113            }
114
115            String parameterName = null;
116            if (i < parameterNames.size()) {
117                parameterName = parameterNames.get(i);
118            }
119
120            parameters.add(ParameterAdaptor.makeTemplate(stg, parameterName, annotationSet));
121        }
122
123        return parameters;
124    }
125
126    private static List<StringTemplate> getAnnotations(StringTemplateGroup stg, AnnotationSetItem annotationSet) {
127        if (annotationSet == null) {
128            return null;
129        }
130
131        List<StringTemplate> annotationAdaptors = new ArrayList<StringTemplate>();
132
133        for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
134            annotationAdaptors.add(AnnotationAdaptor.makeTemplate(stg, annotationItem));
135        }
136        return annotationAdaptors;
137    }
138
139    private static List<MethodItem> getMethodItems(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) {
140        List<MethodItem> methodItems = new ArrayList<MethodItem>();
141
142        MethodItemList methodItemList = new MethodItemList(dexFile, stg, codeItem);
143        methodItemList.generateMethodItemList();
144
145        methodItems.addAll(methodItemList.labels);
146        methodItems.addAll(methodItemList.instructions);
147        methodItems.addAll(methodItemList.blanks);
148        methodItems.addAll(methodItemList.catches);
149        methodItems.addAll(methodItemList.debugItems);
150        Collections.sort(methodItems);
151
152        return methodItems;
153    }
154
155
156    private static class MethodItemList {
157        private final DexFile dexFile;
158        private final StringTemplateGroup stg;
159        private final CodeItem codeItem;
160
161        public HashSet<LabelMethodItem> labels = new HashSet<LabelMethodItem>();
162        public List<MethodItem> instructions = new ArrayList<MethodItem>();
163        public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>();
164        public List<CatchMethodItem> catches = new ArrayList<CatchMethodItem>();
165        public List<MethodItem> debugItems = new ArrayList<MethodItem>();
166
167        private HashMap<Integer, Integer> packedSwitchMap = new HashMap<Integer, Integer>();
168        private HashMap<Integer, Integer> sparseSwitchMap = new HashMap<Integer, Integer>();
169
170        public MethodItemList(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) {
171            this.dexFile = dexFile;
172            this.stg = stg;
173            this.codeItem = codeItem;
174        }
175
176        public void generateMethodItemList() {
177            if (codeItem == null) {
178                return;
179            }
180
181            final byte[] encodedInstructions = codeItem.getEncodedInstructions();
182
183            InstructionIterator.IterateInstructions(encodedInstructions,
184                    new InstructionIterator.ProcessRawInstructionDelegate() {
185                        public void ProcessNormalInstruction(Opcode opcode, int index) {
186                            if (opcode == Opcode.PACKED_SWITCH) {
187                                Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction(
188                                        dexFile, opcode, encodedInstructions, index);
189                                packedSwitchMap.put(index/2 + ins.getOffset(), index/2);
190                            } else if (opcode == Opcode.SPARSE_SWITCH) {
191                                Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction(
192                                        dexFile, opcode, encodedInstructions, index);
193                                sparseSwitchMap.put(index/2 + ins.getOffset(),  index/2);
194                            }
195                        }
196
197                        public void ProcessReferenceInstruction(Opcode opcode, int index) {
198                        }
199
200                        public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) {
201                        }
202
203                        public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) {
204                        }
205
206                        public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount,
207                                                                    int instructionLength) {
208                        }
209                    });
210
211            InstructionIterator.IterateInstructions(dexFile, encodedInstructions,
212                    new InstructionIterator.ProcessInstructionDelegate() {
213                        public void ProcessInstruction(int index, Instruction instruction) {
214                            int offset = index/2;
215                            addMethodItemsForInstruction(offset, instruction);
216                            blanks.add(new BlankMethodItem(stg, offset));
217                        }
218                    });
219
220            blanks.remove(blanks.size()-1);
221
222            addTries();
223
224            addDebugInfo();
225        }
226
227        private void addMethodItemsForInstruction(int offset, Instruction instruction) {
228            switch (instruction.getFormat()) {
229                case Format10t:
230                    instructions.add(new Instruction10tMethodItem(offset, stg,(Instruction10t)instruction));
231                    labels.add(new LabelMethodItem(offset + ((Instruction10t)instruction).getOffset(), stg, "goto_"));
232                    return;
233                case Format10x:
234                    instructions.add(new Instruction10xMethodItem(offset, stg, (Instruction10x)instruction));
235                    return;
236                case Format11n:
237                    instructions.add(new Instruction11nMethodItem(offset, stg, (Instruction11n)instruction));
238                    return;
239                case Format11x:
240                    instructions.add(new Instruction11xMethodItem(offset, stg, (Instruction11x)instruction));
241                    return;
242                case Format12x:
243                    instructions.add(new Instruction12xMethodItem(offset, stg, (Instruction12x)instruction));
244                    return;
245                case Format20t:
246                    instructions.add(new Instruction20tMethodItem(offset, stg, (Instruction20t)instruction));
247                    labels.add(new LabelMethodItem(offset + ((Instruction20t)instruction).getOffset(), stg, "goto_"));
248                    return;
249                case Format21c:
250                    instructions.add(new Instruction21cMethodItem(offset, stg, (Instruction21c)instruction));
251                    return;
252                case Format21h:
253                    instructions.add(new Instruction21hMethodItem(offset, stg, (Instruction21h)instruction));
254                    return;
255                case Format21s:
256                    instructions.add(new Instruction21sMethodItem(offset, stg, (Instruction21s)instruction));
257                    return;
258                case Format21t:
259                    instructions.add(new Instruction21tMethodItem(offset, stg, (Instruction21t)instruction));
260                    labels.add(new LabelMethodItem(offset + ((Instruction21t)instruction).getOffset(), stg, "cond_"));
261                    return;
262                case Format22b:
263                    instructions.add(new Instruction22bMethodItem(offset, stg, (Instruction22b)instruction));
264                    return;
265                case Format22c:
266                    instructions.add(new Instruction22cMethodItem(offset, stg, (Instruction22c)instruction));
267                    return;
268                case Format22s:
269                    instructions.add(new Instruction22sMethodItem(offset, stg, (Instruction22s)instruction));
270                    return;
271                case Format22t:
272                    instructions.add(new Instruction22tMethodItem(offset, stg, (Instruction22t)instruction));
273                    labels.add(new LabelMethodItem(offset + ((Instruction22t)instruction).getOffset(), stg, "cond_"));
274                    return;
275                case Format22x:
276                    instructions.add(new Instruction22xMethodItem(offset, stg, (Instruction22x)instruction));
277                    return;
278                case Format23x:
279                    instructions.add(new Instruction23xMethodItem(offset, stg, (Instruction23x)instruction));
280                    return;
281                case Format30t:
282                    instructions.add(new Instruction30tMethodItem(offset, stg, (Instruction30t)instruction));
283                    labels.add(new LabelMethodItem(offset + ((Instruction30t)instruction).getOffset(), stg, "goto_"));
284                    return;
285                case Format31c:
286                    instructions.add(new Instruction31cMethodItem(offset, stg, (Instruction31c)instruction));
287                    return;
288                case Format31i:
289                    instructions.add(new Instruction31iMethodItem(offset, stg, (Instruction31i)instruction));
290                    return;
291                case Format31t:
292                    instructions.add(new Instruction31tMethodItem(offset, stg, (Instruction31t)instruction));
293                    if (instruction.opcode == Opcode.FILL_ARRAY_DATA) {
294                        labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
295                                "array_"));
296                    } else if (instruction.opcode == Opcode.PACKED_SWITCH) {
297                        labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
298                                "pswitch_data_"));
299                    } else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
300                        labels.add(new LabelMethodItem(offset + ((Instruction31t)instruction).getOffset(), stg,
301                                "sswitch_data_"));
302                    }
303                    return;
304                case Format32x:
305                    instructions.add(new Instruction32xMethodItem(offset, stg, (Instruction32x)instruction));
306                    return;
307                case Format35c:
308                    instructions.add(new Instruction35cMethodItem(offset, stg, (Instruction35c)instruction));
309                    return;
310                case Format3rc:
311                    instructions.add(new Instruction3rcMethodItem(offset, stg, (Instruction3rc)instruction));
312                    return;
313                case Format51l:
314                    instructions.add(new Instruction51lMethodItem(offset, stg, (Instruction51l)instruction));
315                    return;
316                case ArrayData:
317                    instructions.add(new ArrayDataMethodItem(offset, stg, (ArrayDataPseudoInstruction)instruction));
318                    return;
319                case PackedSwitchData:
320                {
321                    final Integer baseAddress = packedSwitchMap.get(offset);
322
323                    if (baseAddress != null) {
324                        PackedSwitchDataPseudoInstruction packedSwitchInstruction =
325                                (PackedSwitchDataPseudoInstruction)instruction;
326
327                        instructions.add(new PackedSwitchMethodItem(offset, stg,
328                                packedSwitchInstruction, baseAddress));
329
330                        Iterator<PackedSwitchDataPseudoInstruction.PackedSwitchTarget> iterator =
331                                packedSwitchInstruction.getTargets();
332                        while (iterator.hasNext()) {
333                            PackedSwitchDataPseudoInstruction.PackedSwitchTarget target = iterator.next();
334                            labels.add(new LabelMethodItem(baseAddress + target.target, stg, "pswitch_"));
335                        }
336                    }
337                    return;
338                }
339                case SparseSwitchData:
340                {
341                    final Integer baseAddress = sparseSwitchMap.get(offset);
342
343                    if (baseAddress != null) {
344                        SparseSwitchDataPseudoInstruction sparseSwitchInstruction =
345                                (SparseSwitchDataPseudoInstruction)instruction;
346
347                        instructions.add(new SparseSwitchMethodItem(offset, stg,
348                                sparseSwitchInstruction, baseAddress));
349
350                        Iterator<SparseSwitchDataPseudoInstruction.SparseSwitchTarget> iterator =
351                                sparseSwitchInstruction.getTargets();
352                        while (iterator.hasNext()) {
353                            SparseSwitchDataPseudoInstruction.SparseSwitchTarget target = iterator.next();
354                            labels.add(new LabelMethodItem(baseAddress + target.target, stg, "sswitch_"));
355                        }
356                    }
357                }
358            }
359        }
360
361        private void addTries() {
362            if (codeItem.getTries() == null) {
363                return;
364            }
365            for (CodeItem.TryItem tryItem: codeItem.getTries()) {
366                int startAddress = tryItem.startAddress;
367                int endAddress = tryItem.startAddress + tryItem.instructionCount;
368
369                /**
370                 * The end address points to the address immediately after the end of the last
371                 * instruction that the try block covers. We want the .catch directive and end_try
372                 * label to be associated with the last covered instruction, so we need to get
373                 * the offset for that instruction
374                 */
375                int index = Collections.binarySearch(instructions, new BlankMethodItem(stg, endAddress));
376                if (index < 0) {
377                    index = (index * -1) - 1;
378                }
379                //index should never by 0, so this should be safe
380                if (index == instructions.size()) {
381                    //if the end address is the same as the address of the last instruction, then
382                    //this try item ends at the next to last instruction.
383                    //otherwise, if the end address is past the address of the last instruction,
384                    //thin this try item ends at the last instruction
385                    if (instructions.get(instructions.size() - 1).getOffset() == endAddress) {
386                        //get the address for the next to last instruction
387                        index -= 2;
388                    } else {
389                        //get the address for the last instruction
390                        index--;
391                    }
392                } else {
393                    index -= 2;
394                }
395
396                int lastInstructionOffset = instructions.get(index).getOffset();
397
398                //add the catch all handler if it exists
399                int catchAllAddress = tryItem.encodedCatchHandler.catchAllHandlerAddress;
400                if (catchAllAddress != -1) {
401                    CatchMethodItem catchMethodItem = new CatchMethodItem(lastInstructionOffset, stg, null,
402                            startAddress, endAddress, catchAllAddress) {
403                        public String getTemplateName() {
404                            return "CatchAll";
405                        }
406                    };
407                    catches.add(catchMethodItem);
408
409                    labels.add(new LabelMethodItem(startAddress, stg, "try_start_"));
410                    //use the offset from the last covered instruction, but make the label
411                    //name refer to the address of the next instruction
412                    labels.add(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress));
413                    labels.add(new LabelMethodItem(catchAllAddress, stg, "handler_"));
414
415                }
416
417                //add the rest of the handlers
418                //TODO: find adjacent handlers for the same type and combine them
419                for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
420                    //use the offset from the last covered instruction
421                    CatchMethodItem catchMethodItem = new CatchMethodItem(lastInstructionOffset, stg,
422                            handler.exceptionType, startAddress, endAddress, handler.handlerAddress);
423                    catches.add(catchMethodItem);
424
425                    labels.add(new LabelMethodItem(startAddress, stg, "try_start_"));
426                    //use the offset from the last covered instruction, but make the label
427                    //name refer to the address of the next instruction
428                    labels.add(new EndTryLabelMethodItem(lastInstructionOffset, stg, endAddress));
429                    labels.add(new LabelMethodItem(handler.handlerAddress, stg, "handler_"));
430                }
431            }
432        }
433
434        private void addDebugInfo() {
435            DebugInfoItem debugInfoItem = codeItem.getDebugInfo();
436            if (debugInfoItem == null) {
437                return;
438            }
439
440            DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(),
441                    new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() {
442                        @Override
443                        public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
444                                                      TypeIdItem type) {
445                            debugItems.add(new LocalDebugMethodItem(codeAddress, stg, "StartLocal", -1, registerNum,
446                                    name, type, null));
447                        }
448
449                        @Override
450                        public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum,
451                                                              StringIdItem name, TypeIdItem type,
452                                                              StringIdItem signature) {
453                            debugItems.add(new LocalDebugMethodItem(codeAddress, stg, "StartLocal", -1, registerNum,
454                                    name, type, signature));
455                        }
456
457                        @Override
458                        public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name,
459                                                    TypeIdItem type, StringIdItem signature) {
460                            debugItems.add(new LocalDebugMethodItem(codeAddress, stg, "EndLocal", -1, registerNum, name,
461                                    type, signature));
462                        }
463
464                        @Override
465                        public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
466                                                        TypeIdItem type, StringIdItem signature) {
467                            debugItems.add(new LocalDebugMethodItem(codeAddress, stg, "RestartLocal", -1, registerNum,
468                                    name, type, signature));
469                        }
470
471                        @Override
472                        public void ProcessSetPrologueEnd(int codeAddress) {
473                            debugItems.add(new DebugMethodItem(codeAddress, stg, "EndPrologue", -4));
474                        }
475
476                        @Override
477                        public void ProcessSetEpilogueBegin(int codeAddress) {
478                            debugItems.add(new DebugMethodItem(codeAddress, stg, "StartEpilogue", -4));
479                        }
480
481                        @Override
482                        public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) {
483                            debugItems.add(new DebugMethodItem(codeAddress, stg, "SetFile", -3) {
484                                @Override
485                                protected void setAttributes(StringTemplate template) {
486                                    template.setAttribute("FileName", name.getStringValue());
487                                }
488                            });
489                        }
490
491                        @Override
492                        public void ProcessLineEmit(int codeAddress, final int line) {
493                             debugItems.add(new DebugMethodItem(codeAddress, stg, "Line", -2) {
494                                 @Override
495                                 protected void setAttributes(StringTemplate template) {
496                                     template.setAttribute("Line", line);
497                                 }
498                             });
499                        }
500                    });
501        }
502    }
503}
504