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