MethodDefinition.java revision 2bdbf739bfd935877e463bc36df0e446b1dfb09f
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.baksmali.main; 34import org.jf.dexlib.*; 35import org.jf.dexlib.Code.*; 36import org.jf.dexlib.Code.Analysis.AnalyzedInstruction; 37import org.jf.dexlib.Code.Analysis.MethodAnalyzer; 38import org.jf.dexlib.Code.Analysis.RegisterType; 39import org.jf.dexlib.Code.Analysis.ValidationException; 40import org.jf.dexlib.Debug.DebugInstructionIterator; 41import org.jf.dexlib.Util.AccessFlags; 42import org.antlr.stringtemplate.StringTemplateGroup; 43import org.antlr.stringtemplate.StringTemplate; 44import org.jf.dexlib.Util.Hex; 45import org.jf.dexlib.Util.SparseIntArray; 46 47import java.util.*; 48 49public class MethodDefinition { 50 private final StringTemplateGroup stg; 51 private final ClassDataItem.EncodedMethod encodedMethod; 52 private final MethodAnalyzer methodAnalyzer; 53 54 private final LabelCache labelCache = new LabelCache(); 55 56 private final SparseIntArray packedSwitchMap; 57 private final SparseIntArray sparseSwitchMap; 58 private final SparseIntArray instructionMap; 59 60 private final int registerCount; 61 62 public MethodDefinition(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod) { 63 this.stg = stg; 64 this.encodedMethod = encodedMethod; 65 66 //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh. 67 68 if (encodedMethod.codeItem != null) { 69 methodAnalyzer = new MethodAnalyzer(encodedMethod); 70 AnalyzedInstruction[] instructions = methodAnalyzer.makeInstructionArray(); 71 72 packedSwitchMap = new SparseIntArray(1); 73 sparseSwitchMap = new SparseIntArray(1); 74 instructionMap = new SparseIntArray(instructions.length); 75 76 registerCount = encodedMethod.codeItem.getRegisterCount(); 77 78 int currentCodeAddress = 0; 79 for (int i=0; i<instructions.length; i++) { 80 AnalyzedInstruction instruction = instructions[i]; 81 if (instruction.instruction.opcode == Opcode.PACKED_SWITCH) { 82 packedSwitchMap.append( 83 currentCodeAddress + ((OffsetInstruction)instruction.instruction).getTargetAddressOffset(), 84 currentCodeAddress); 85 } else if (instruction.instruction.opcode == Opcode.SPARSE_SWITCH) { 86 sparseSwitchMap.append( 87 currentCodeAddress + ((OffsetInstruction)instruction.instruction).getTargetAddressOffset(), 88 currentCodeAddress); 89 } 90 instructionMap.append(currentCodeAddress, i); 91 currentCodeAddress += instruction.instruction.getSize(currentCodeAddress); 92 } 93 } else { 94 packedSwitchMap = null; 95 sparseSwitchMap = null; 96 instructionMap = null; 97 methodAnalyzer = null; 98 registerCount = 0; 99 } 100 } 101 102 public StringTemplate createTemplate(AnnotationSetItem annotationSet, 103 AnnotationSetRefList parameterAnnotations) { 104 105 CodeItem codeItem = encodedMethod.codeItem; 106 107 StringTemplate template = stg.getInstanceOf("method"); 108 109 template.setAttribute("AccessFlags", getAccessFlags(encodedMethod)); 110 template.setAttribute("MethodName", encodedMethod.method.getMethodName().getStringValue()); 111 template.setAttribute("Prototype", encodedMethod.method.getPrototype().getPrototypeString()); 112 template.setAttribute("HasCode", codeItem != null); 113 template.setAttribute("RegistersDirective", baksmali.useLocalsDirective?".locals":".registers"); 114 template.setAttribute("RegisterCount", codeItem==null?"0":Integer.toString(getRegisterCount(encodedMethod))); 115 template.setAttribute("Parameters", getParameters(stg, codeItem, parameterAnnotations)); 116 template.setAttribute("Annotations", getAnnotations(stg, annotationSet)); 117 template.setAttribute("MethodItems", getMethodItems()); 118 119 return template; 120 } 121 122 private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod) 123 { 124 int totalRegisters = encodedMethod.codeItem.getRegisterCount(); 125 if (baksmali.useLocalsDirective) { 126 int parameterRegisters = encodedMethod.method.getPrototype().getParameterRegisterCount(); 127 if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) { 128 parameterRegisters++; 129 } 130 return totalRegisters - parameterRegisters; 131 } 132 return totalRegisters; 133 } 134 135 private static List<String> getAccessFlags(ClassDataItem.EncodedMethod encodedMethod) { 136 List<String> accessFlags = new ArrayList<String>(); 137 138 for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) { 139 accessFlags.add(accessFlag.toString()); 140 } 141 142 return accessFlags; 143 } 144 145 private static List<StringTemplate> getParameters(StringTemplateGroup stg, CodeItem codeItem, 146 AnnotationSetRefList parameterAnnotations) { 147 DebugInfoItem debugInfoItem = null; 148 if (baksmali.outputDebugInfo && codeItem != null) { 149 debugInfoItem = codeItem.getDebugInfo(); 150 } 151 152 int parameterCount = 0; 153 154 List<AnnotationSetItem> annotations = new ArrayList<AnnotationSetItem>(); 155 if (parameterAnnotations != null) { 156 AnnotationSetItem[] _annotations = parameterAnnotations.getAnnotationSets(); 157 if (_annotations != null) { 158 annotations.addAll(Arrays.asList(_annotations)); 159 } 160 161 parameterCount = annotations.size(); 162 } 163 164 List<String> parameterNames = new ArrayList<String>(); 165 if (debugInfoItem != null) { 166 StringIdItem[] _parameterNames = debugInfoItem.getParameterNames(); 167 if (_parameterNames != null) { 168 for (StringIdItem parameterName: _parameterNames) { 169 parameterNames.add(parameterName==null?null:parameterName.getStringValue()); 170 } 171 } 172 173 if (parameterCount < parameterNames.size()) { 174 parameterCount = parameterNames.size(); 175 } 176 } 177 178 List<StringTemplate> parameters = new ArrayList<StringTemplate>(); 179 for (int i=0; i<parameterCount; i++) { 180 AnnotationSetItem annotationSet = null; 181 if (i < annotations.size()) { 182 annotationSet = annotations.get(i); 183 } 184 185 String parameterName = null; 186 if (i < parameterNames.size()) { 187 parameterName = parameterNames.get(i); 188 } 189 190 parameters.add(ParameterAdaptor.createTemplate(stg, parameterName, annotationSet)); 191 } 192 193 return parameters; 194 } 195 196 public LabelCache getLabelCache() { 197 return labelCache; 198 } 199 200 public ValidationException getValidationException() { 201 if (methodAnalyzer == null) { 202 return null; 203 } 204 205 return methodAnalyzer.getValidationException(); 206 } 207 208 public int getPackedSwitchBaseAddress(int packedSwitchDataAddress) { 209 int packedSwitchBaseAddress = this.packedSwitchMap.get(packedSwitchDataAddress, -1); 210 211 if (packedSwitchBaseAddress == -1) { 212 throw new RuntimeException("Could not find the packed switch statement corresponding to the packed " + 213 "switch data at address " + packedSwitchDataAddress); 214 } 215 216 return packedSwitchBaseAddress; 217 } 218 219 public int getSparseSwitchBaseAddress(int sparseSwitchDataAddress) { 220 int sparseSwitchBaseAddress = this.sparseSwitchMap.get(sparseSwitchDataAddress, -1); 221 222 if (sparseSwitchBaseAddress == -1) { 223 throw new RuntimeException("Could not find the sparse switch statement corresponding to the sparse " + 224 "switch data at address " + sparseSwitchDataAddress); 225 } 226 227 return sparseSwitchBaseAddress; 228 } 229 230 private static List<StringTemplate> getAnnotations(StringTemplateGroup stg, AnnotationSetItem annotationSet) { 231 if (annotationSet == null) { 232 return null; 233 } 234 235 List<StringTemplate> annotationAdaptors = new ArrayList<StringTemplate>(); 236 237 for (AnnotationItem annotationItem: annotationSet.getAnnotations()) { 238 annotationAdaptors.add(AnnotationAdaptor.createTemplate(stg, annotationItem)); 239 } 240 return annotationAdaptors; 241 } 242 243 private List<MethodItem> getMethodItems() { 244 List<MethodItem> methodItems = new ArrayList<MethodItem>(); 245 246 if (encodedMethod.codeItem == null) { 247 return methodItems; 248 } 249 250 AnalyzedInstruction[] instructions; 251 if (baksmali.registerInfo != 0) { 252 instructions = methodAnalyzer.analyze(); 253 254 ValidationException validationException = methodAnalyzer.getValidationException(); 255 if (validationException != null) { 256 methodItems.add(new CommentMethodItem(stg, 257 String.format("ValidationException: %s" ,validationException.getMessage()), 258 validationException.getCodeAddress(), Integer.MIN_VALUE)); 259 } 260 } else { 261 instructions = methodAnalyzer.makeInstructionArray(); 262 } 263 264 BitSet printPreRegister = new BitSet(registerCount); 265 BitSet printPostRegister = new BitSet(registerCount); 266 267 int currentCodeAddress = 0; 268 for (int i=0; i<instructions.length; i++) { 269 AnalyzedInstruction instruction = instructions[i]; 270 271 methodItems.add(InstructionMethodItemFactory.makeInstructionFormatMethodItem(this, 272 encodedMethod.codeItem, currentCodeAddress, stg, instruction.instruction)); 273 274 if (i != instructions.length - 1) { 275 methodItems.add(new BlankMethodItem(stg, currentCodeAddress)); 276 } 277 278 if (baksmali.addCodeOffsets) { 279 methodItems.add(new CommentMethodItem(stg, String.format("@%x", currentCodeAddress), 280 currentCodeAddress, -1000)); 281 } 282 283 if (baksmali.registerInfo != 0 && !instruction.instruction.getFormat().variableSizeFormat) { 284 printPreRegister.clear(); 285 printPostRegister.clear(); 286 287 if ((baksmali.registerInfo & main.ALL) != 0) { 288 printPreRegister.set(0, registerCount); 289 printPostRegister.set(0, registerCount); 290 } else { 291 if ((baksmali.registerInfo & main.ALLPRE) != 0) { 292 printPreRegister.set(0, registerCount); 293 } else { 294 if ((baksmali.registerInfo & main.ARGS) != 0) { 295 addArgsRegs(printPreRegister, instruction); 296 } 297 if ((baksmali.registerInfo & main.MERGE) != 0) { 298 addMergeRegs(printPreRegister, instructions, i); 299 } else if ((baksmali.registerInfo & main.FULLMERGE) != 0 && 300 (i == 0 || instruction.isBeginningInstruction())) { 301 addParamRegs(printPreRegister); 302 } 303 } 304 305 if ((baksmali.registerInfo & main.ALLPOST) != 0) { 306 printPostRegister.set(0, registerCount); 307 } else if ((baksmali.registerInfo & main.DEST) != 0) { 308 addDestRegs(printPostRegister, instruction); 309 } 310 } 311 312 if ((baksmali.registerInfo & main.FULLMERGE) != 0) { 313 addFullMergeRegs(printPreRegister, methodItems, methodAnalyzer, i, currentCodeAddress); 314 } 315 316 if (!printPreRegister.isEmpty()) { 317 methodItems.add(new CommentMethodItem(stg, 318 getPreInstructionRegisterString(instruction, printPreRegister), 319 currentCodeAddress, 99.9)); 320 } 321 322 if (!printPostRegister.isEmpty()) { 323 methodItems.add(new CommentMethodItem(stg, 324 getPostInstructionRegisterString(instruction, printPostRegister), 325 currentCodeAddress, 100.1)); 326 } 327 } 328 329 currentCodeAddress += instruction.instruction.getSize(currentCodeAddress); 330 } 331 332 addTries(methodItems); 333 addDebugInfo(methodItems); 334 335 if (baksmali.useSequentialLabels) { 336 setLabelSequentialNumbers(); 337 } 338 339 340 for (LabelMethodItem labelMethodItem: labelCache.getLabels()) { 341 if (labelMethodItem.isCommentedOut()) { 342 methodItems.add(new CommentedOutMethodItem(stg, labelMethodItem)); 343 } else { 344 methodItems.add(labelMethodItem); 345 } 346 } 347 348 Collections.sort(methodItems); 349 350 return methodItems; 351 } 352 353 private void addArgsRegs(BitSet printPreRegister, AnalyzedInstruction analyzedInstruction) { 354 if (analyzedInstruction.instruction instanceof RegisterRangeInstruction) { 355 RegisterRangeInstruction instruction = (RegisterRangeInstruction)analyzedInstruction.instruction; 356 357 printPreRegister.set(instruction.getStartRegister(), 358 instruction.getStartRegister() + instruction.getRegCount()); 359 } else if (analyzedInstruction.instruction instanceof FiveRegisterInstruction) { 360 FiveRegisterInstruction instruction = (FiveRegisterInstruction)analyzedInstruction.instruction; 361 int regCount = instruction.getRegCount(); 362 switch (regCount) { 363 case 5: 364 printPreRegister.set(instruction.getRegisterA()); 365 //fall through 366 case 4: 367 printPreRegister.set(instruction.getRegisterG()); 368 //fall through 369 case 3: 370 printPreRegister.set(instruction.getRegisterF()); 371 //fall through 372 case 2: 373 printPreRegister.set(instruction.getRegisterE()); 374 //fall through 375 case 1: 376 printPreRegister.set(instruction.getRegisterD()); 377 } 378 } else if (analyzedInstruction.instruction instanceof ThreeRegisterInstruction) { 379 ThreeRegisterInstruction instruction = (ThreeRegisterInstruction)analyzedInstruction.instruction; 380 printPreRegister.set(instruction.getRegisterA()); 381 printPreRegister.set(instruction.getRegisterB()); 382 printPreRegister.set(instruction.getRegisterC()); 383 } else if (analyzedInstruction.instruction instanceof TwoRegisterInstruction) { 384 TwoRegisterInstruction instruction = (TwoRegisterInstruction)analyzedInstruction.instruction; 385 printPreRegister.set(instruction.getRegisterA()); 386 printPreRegister.set(instruction.getRegisterB()); 387 } else if (analyzedInstruction.instruction instanceof SingleRegisterInstruction) { 388 SingleRegisterInstruction instruction = (SingleRegisterInstruction)analyzedInstruction.instruction; 389 printPreRegister.set(instruction.getRegisterA()); 390 } 391 } 392 393 private void addFullMergeRegs(BitSet printPreRegister, List<MethodItem> methodItems, MethodAnalyzer methodAnalyzer, 394 int instructionNum, int currentCodeAddress) { 395 if (instructionNum == 0) { 396 return; 397 } 398 399 //MethodAnalyzer cached the analyzedInstructions, so we're not actually re-analyzing, just getting the 400 //instructions that have already been analyzed 401 AnalyzedInstruction[] instructions = methodAnalyzer.analyze(); 402 AnalyzedInstruction instruction = instructions[instructionNum]; 403 404 if (instruction.getPredecessorCount() <= 1) { 405 return; 406 } 407 408 StringBuffer sb = new StringBuffer(); 409 410 for (int registerNum=0; registerNum<registerCount; registerNum++) { 411 sb.setLength(0); 412 sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem, registerNum)); 413 sb.append('='); 414 sb.append(instruction.getPreInstructionRegisterType(registerNum)); 415 sb.append(":merge{"); 416 417 RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum); 418 boolean addRegister = false; 419 420 boolean first = true; 421 for (AnalyzedInstruction predecessor: instruction.getPredecessors()) { 422 RegisterType predecessorRegisterType = predecessor.getPostInstructionRegisterType(registerNum); 423 424 if (!first) { 425 sb.append(','); 426 if (!addRegister && mergedRegisterType != predecessorRegisterType) { 427 addRegister = true; 428 } 429 } 430 431 if (predecessor.getInstructionIndex() == -1) { 432 //the fake "StartOfMethod" instruction 433 sb.append("Start:"); 434 } else { 435 sb.append("0x"); 436 sb.append(Integer.toHexString(methodAnalyzer.getInstructionAddress(predecessor))); 437 sb.append(':'); 438 } 439 sb.append(predecessor.getPostInstructionRegisterType(registerNum).toString()); 440 first = false; 441 } 442 443 if (!addRegister) { 444 continue; 445 } 446 447 sb.append("}"); 448 449 methodItems.add(new CommentMethodItem(stg, sb.toString(), currentCodeAddress, 99.8)); 450 printPreRegister.clear(registerNum); 451 } 452 } 453 454 private void addMergeRegs(BitSet printPreRegister, AnalyzedInstruction instructions[], int instructionNum) { 455 //MethodAnalyzer cached the analyzedInstructions, so we're not actually re-analyzing, just getting the 456 //instructions that have already been analyzed 457 AnalyzedInstruction instruction = instructions[instructionNum]; 458 459 if (instructionNum == 0) { 460 addParamRegs(printPreRegister); 461 } else { 462 if (instruction.isBeginningInstruction()) { 463 addParamRegs(printPreRegister); 464 } 465 466 if (instruction.getPredecessorCount() <= 1) { 467 //in the common case of an instruction that only has a single predecessor which is the previous 468 //instruction, the pre-instruction registers will always match the previous instruction's 469 //post-instruction registers 470 return; 471 } 472 473 for (int registerNum=0; registerNum<registerCount; registerNum++) { 474 RegisterType mergedRegisterType = instruction.getPreInstructionRegisterType(registerNum); 475 476 for (AnalyzedInstruction predecessor: instruction.getPredecessors()) { 477 if (predecessor.getPostInstructionRegisterType(registerNum) != mergedRegisterType) { 478 printPreRegister.set(registerNum); 479 continue; 480 } 481 } 482 } 483 } 484 } 485 486 private void addParamRegs(BitSet printPreRegister) { 487 int registerCount = encodedMethod.codeItem.getRegisterCount(); 488 489 int parameterRegisterCount = encodedMethod.method.getPrototype().getParameterRegisterCount(); 490 if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) { 491 parameterRegisterCount++; 492 } 493 494 printPreRegister.set(registerCount-parameterRegisterCount, registerCount); 495 } 496 497 private void addDestRegs(BitSet printPostRegister, AnalyzedInstruction analyzedInstruction) { 498 for (int registerNum=0; registerNum<registerCount; registerNum++) { 499 if (analyzedInstruction.getPreInstructionRegisterType(registerNum) != 500 analyzedInstruction.getPostInstructionRegisterType(registerNum)) { 501 printPostRegister.set(registerNum); 502 } 503 } 504 } 505 506 507 private String getPreInstructionRegisterString(AnalyzedInstruction instruction, BitSet registers) { 508 StringBuilder sb = new StringBuilder(); 509 510 for (int registerNum = registers.nextSetBit(0); registerNum >= 0; 511 registerNum = registers.nextSetBit(registerNum + 1)) { 512 513 RegisterType registerType = instruction.getPreInstructionRegisterType(registerNum); 514 sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem,registerNum)); 515 sb.append("="); 516 if (registerType == null) { 517 sb.append("null"); 518 } else { 519 sb.append(registerType.toString()); 520 } 521 sb.append(";"); 522 } 523 524 return sb.toString(); 525 } 526 527 private String getPostInstructionRegisterString(AnalyzedInstruction instruction, BitSet registers) { 528 StringBuilder sb = new StringBuilder(); 529 530 for (int registerNum = registers.nextSetBit(0); registerNum >= 0; 531 registerNum = registers.nextSetBit(registerNum + 1)) { 532 533 RegisterType registerType = instruction.getPostInstructionRegisterType(registerNum); 534 sb.append(RegisterFormatter.formatRegister(encodedMethod.codeItem,registerNum)); 535 sb.append("="); 536 if (registerType == null) { 537 sb.append("null"); 538 } else { 539 sb.append(registerType.toString()); 540 } 541 sb.append(";"); 542 } 543 544 return sb.toString(); 545 } 546 547 private void addTries(List<MethodItem> methodItems) { 548 if (encodedMethod.codeItem == null || encodedMethod.codeItem.getTries() == null) { 549 return; 550 } 551 552 Instruction[] instructions = encodedMethod.codeItem.getInstructions(); 553 554 for (CodeItem.TryItem tryItem: encodedMethod.codeItem.getTries()) { 555 int startAddress = tryItem.getStartCodeAddress(); 556 int endAddress = tryItem.getStartCodeAddress() + tryItem.getTryLength(); 557 558 /** 559 * The end address points to the address immediately after the end of the last 560 * instruction that the try block covers. We want the .catch directive and end_try 561 * label to be associated with the last covered instruction, so we need to get 562 * the address for that instruction 563 */ 564 565 int index = instructionMap.get(endAddress, -1); 566 int lastInstructionAddress; 567 568 /** 569 * If we couldn't find the index, then the try block probably extends to the last instruction in the 570 * method, and so endAddress would be the address immediately after the end of the last instruction. 571 * Check to make sure this is the case, if not, throw an exception. 572 */ 573 if (index == -1) { 574 Instruction lastInstruction = instructions[instructions.length - 1]; 575 lastInstructionAddress = instructionMap.keyAt(instructionMap.size() - 1); 576 577 if (endAddress != lastInstructionAddress + lastInstruction.getSize(lastInstructionAddress)) { 578 throw new RuntimeException("Invalid code offset " + endAddress + " for the try block end address"); 579 } 580 } else { 581 if (index == 0) { 582 throw new RuntimeException("Unexpected instruction index"); 583 } 584 Instruction lastInstruction = instructions[index - 1]; 585 586 if (lastInstruction.getFormat().variableSizeFormat) { 587 throw new RuntimeException("This try block unexpectedly ends on a switch/array data block."); 588 } 589 590 //getSize for non-variable size formats should return the same size regardless of code address, so just 591 //use a dummy address of "0" 592 lastInstructionAddress = endAddress - lastInstruction.getSize(0); 593 } 594 595 //add the catch all handler if it exists 596 int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress(); 597 if (catchAllAddress != -1) { 598 CatchMethodItem catchAllMethodItem = new CatchMethodItem(labelCache, lastInstructionAddress, stg, null, 599 startAddress, endAddress, catchAllAddress); 600 methodItems.add(catchAllMethodItem); 601 } 602 603 //add the rest of the handlers 604 for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) { 605 //use the address from the last covered instruction 606 CatchMethodItem catchMethodItem = new CatchMethodItem(labelCache, lastInstructionAddress, stg, 607 handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress()); 608 methodItems.add(catchMethodItem); 609 } 610 } 611 } 612 613 private void addDebugInfo(final List<MethodItem> methodItems) { 614 if (encodedMethod.codeItem == null || encodedMethod.codeItem.getDebugInfo() == null) { 615 return; 616 } 617 618 final CodeItem codeItem = encodedMethod.codeItem; 619 DebugInfoItem debugInfoItem = codeItem.getDebugInfo(); 620 621 DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(), 622 new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() { 623 @Override 624 public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name, 625 TypeIdItem type) { 626 methodItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", 627 -1, registerNum, name, type, null)); 628 } 629 630 @Override 631 public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum, 632 StringIdItem name, TypeIdItem type, 633 StringIdItem signature) { 634 methodItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", 635 -1, registerNum, name, type, signature)); 636 } 637 638 @Override 639 public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name, 640 TypeIdItem type, StringIdItem signature) { 641 methodItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "EndLocal", -1, 642 registerNum, name, type, signature)); 643 } 644 645 @Override 646 public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name, 647 TypeIdItem type, StringIdItem signature) { 648 methodItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "RestartLocal", -1, 649 registerNum, name, type, signature)); 650 } 651 652 @Override 653 public void ProcessSetPrologueEnd(int codeAddress) { 654 methodItems.add(new DebugMethodItem(codeAddress, stg, "EndPrologue", -4)); 655 } 656 657 @Override 658 public void ProcessSetEpilogueBegin(int codeAddress) { 659 methodItems.add(new DebugMethodItem(codeAddress, stg, "StartEpilogue", -4)); 660 } 661 662 @Override 663 public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) { 664 methodItems.add(new DebugMethodItem(codeAddress, stg, "SetFile", -3) { 665 @Override 666 protected void setAttributes(StringTemplate template) { 667 template.setAttribute("FileName", name.getStringValue()); 668 } 669 }); 670 } 671 672 @Override 673 public void ProcessLineEmit(int codeAddress, final int line) { 674 methodItems.add(new DebugMethodItem(codeAddress, stg, "Line", -2) { 675 @Override 676 protected void setAttributes(StringTemplate template) { 677 template.setAttribute("Line", line); 678 } 679 }); 680 } 681 }); 682 } 683 684 private void setLabelSequentialNumbers() { 685 HashMap<String, Integer> nextLabelSequenceByType = new HashMap<String, Integer>(); 686 ArrayList<LabelMethodItem> sortedLabels = new ArrayList<LabelMethodItem>(labelCache.getLabels()); 687 688 //sort the labels by their location in the method 689 Collections.sort(sortedLabels); 690 691 for (LabelMethodItem labelMethodItem: sortedLabels) { 692 Integer labelSequence = nextLabelSequenceByType.get(labelMethodItem.getLabelPrefix()); 693 if (labelSequence == null) { 694 labelSequence = 0; 695 } 696 labelMethodItem.setLabelSequence(labelSequence); 697 nextLabelSequenceByType.put(labelMethodItem.getLabelPrefix(), labelSequence + 1); 698 } 699 } 700 701 public static class LabelCache { 702 protected HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>(); 703 704 public LabelCache() { 705 } 706 707 public LabelMethodItem internLabel(LabelMethodItem labelMethodItem) { 708 LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem); 709 if (internedLabelMethodItem != null) { 710 if (!labelMethodItem.isCommentedOut()) { 711 internedLabelMethodItem.setUncommented(); 712 } 713 return internedLabelMethodItem; 714 } 715 labels.put(labelMethodItem, labelMethodItem); 716 return labelMethodItem; 717 } 718 719 720 public Collection<LabelMethodItem> getLabels() { 721 return labels.values(); 722 } 723 } 724} 725