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