1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dasm; 18 19 import com.android.dx.dex.DexOptions; 20 import com.android.dx.dex.code.ArrayData; 21 import com.android.dx.dex.code.CodeAddress; 22 import com.android.dx.dex.code.CstInsn; 23 import com.android.dx.dex.code.DalvCode; 24 import com.android.dx.dex.code.DalvInsn; 25 import com.android.dx.dex.code.Dops; 26 import com.android.dx.dex.code.OddSpacer; 27 import com.android.dx.dex.code.OutputFinisher; 28 import com.android.dx.dex.code.PositionList; 29 import com.android.dx.dex.code.SimpleInsn; 30 import com.android.dx.dex.code.SwitchData; 31 import com.android.dx.dex.code.TargetInsn; 32 import com.android.dx.dex.code.form.Form51l; 33 import com.android.dx.dex.file.ClassDefItem; 34 import com.android.dx.dex.file.DexFile; 35 import com.android.dx.dex.file.EncodedField; 36 import com.android.dx.dex.file.EncodedMethod; 37 import com.android.dx.rop.code.AccessFlags; 38 import com.android.dx.rop.code.RegisterSpec; 39 import com.android.dx.rop.code.RegisterSpecList; 40 import com.android.dx.rop.code.SourcePosition; 41 import com.android.dx.rop.cst.Constant; 42 import com.android.dx.rop.cst.CstBoolean; 43 import com.android.dx.rop.cst.CstByte; 44 import com.android.dx.rop.cst.CstChar; 45 import com.android.dx.rop.cst.CstDouble; 46 import com.android.dx.rop.cst.CstFieldRef; 47 import com.android.dx.rop.cst.CstFloat; 48 import com.android.dx.rop.cst.CstInteger; 49 import com.android.dx.rop.cst.CstLong; 50 import com.android.dx.rop.cst.CstMethodRef; 51 import com.android.dx.rop.cst.CstNat; 52 import com.android.dx.rop.cst.CstShort; 53 import com.android.dx.rop.cst.CstString; 54 import com.android.dx.rop.cst.CstType; 55 import com.android.dx.rop.type.StdTypeList; 56 import com.android.dx.rop.type.Type; 57 import com.android.dx.rop.type.TypeList; 58 import com.android.dx.util.IntList; 59 60 import java.io.FileWriter; 61 import java.io.IOException; 62 import java.io.OutputStream; 63 import java.io.Reader; 64 import java.util.ArrayList; 65 import java.util.Enumeration; 66 import java.util.Hashtable; 67 import java.util.Vector; 68 69 //TODO: copyright notice 70 71 /** 72 * This class represents the public API for Dasm. It has two main methods (readD 73 * and write) and few utility methods. To compile .d file: -create DAsm instance 74 * -call readD() to read and parse content of .d file -call write() to write out 75 * binary representation of .d file. .d file can contain several classes and/or 76 * intefaces declarations. 77 */ 78 79 public class DAsm { 80 private static final boolean PARSER_DEBUG = false; 81 82 // number of errors reported in a file. 83 int errors; 84 85 // options for dex output 86 DexOptions dexOptions = new DexOptions(); 87 88 // file being processed 89 DexFile dexFile; 90 int line_num; 91 Scanner scanner; 92 93 // state info for the class being built 94 boolean class_header; 95 String class_name; 96 int class_acc; 97 String superclass_name; 98 String source_name; 99 String filename; 100 Vector<String> interfaces = new Vector<String>(); 101 ClassDefItem classDef; 102 103 // method being built 104 EncodedMethod enc_method; 105 CstNat method_nat; 106 int method_acc; 107 int regs_count; 108 OutputFinisher output_finisher; 109 110 /** 111 * list of exceptions that method can throw. 112 */ 113 Vector<String> throw_list = new Vector<String>(); 114 115 /** 116 * Constructor of CatchTable instances from method data. 117 */ 118 DasmCatchBuilder catch_builder; 119 120 /** 121 * Holds CodeAddress associated with particular label and <i>planted</i> 122 * attribute specifying that CodeAddress was added to instructions array. 123 * <i>planted</i> is false if this label is a target of forward branch and 124 * it was not added to instructions array yet. 125 */ 126 class LabelTableEntry { 127 LabelTableEntry(CodeAddress code_address, boolean planted) { 128 this.code_address = code_address; 129 this.planted = planted; 130 } 131 132 CodeAddress code_address; 133 boolean planted; 134 } 135 136 /** 137 * Hold a translation table "LabelX" -> CodeAddress, planted. 138 */ 139 Hashtable<String, LabelTableEntry> labels_table; 140 141 /** 142 * used by relative forward jumps. When relative forward offset is found, 143 * CodeAddress is placed into unprocessed_relative_goto_addr. When addInsn 144 * method is called, it checks if there was a jump to current instruction 145 * and moves CodeAddress from unprocessed_relative_goto_addr into 146 * output_finisher. 147 */ 148 int current_insn_number; 149 Hashtable<Integer, CodeAddress> unprocessed_relative_goto_addr = 150 new Hashtable<Integer, CodeAddress>(); 151 152 // fill-array-data data 153 int fill_data_reg; 154 String fill_array_data_type; 155 Vector<Number> fill_array_data_values; 156 157 // packed-switch and sparse-switch data 158 int switch_reg; 159 Vector<Object> switch_targets; 160 IntList switch_keys; 161 int packed_switch_first_key; 162 int packed_switch_current_key; 163 164 /** 165 * holds sparse-switch, packed-switch and fill-array-data data blocks to be 166 * added at the end of method 167 */ 168 Vector<DalvInsn> data_blocks = new Vector<DalvInsn>(); 169 170 /** 171 * Returns the number of warnings/errors encountered while parsing a file. 0 172 * if everything went OK. 173 */ 174 public int errorCount() { 175 return errors; 176 } 177 178 void report_error(String msg) { 179 errors++; 180 System.out.println("Line " + line_num + ": " + msg); 181 } 182 183 void throwDasmError(String msg) throws DasmError { 184 throw new DasmError("Line " + line_num + ": " + msg); 185 } 186 187 /** 188 * used by .line directive 189 */ 190 void addLineInfo(int line_num) throws DasmError { 191 throw new IllegalStateException(".line not implemented"); 192 } 193 194 void addLine(int line_num) throws DasmError { 195 throw new IllegalStateException(".line not implemented"); 196 } 197 198 /** 199 * used by the .var directive 200 */ 201 void addVar(String startLab, String endLab, String name, String desc, 202 String sign, int var_num) throws DasmError { 203 throw new IllegalStateException(".var is not implemented"); 204 } 205 206 void addVar(int startOffset, int endOffset, String name, String desc, 207 String sign, int var_num) throws DasmError { 208 throw new IllegalStateException(".var is not implemented"); 209 } 210 211 212 /** 213 * Used by the parser to tell DAsm what the line number for the next 214 * statement is. DAsm's autoNumber mechanism uses this info. 215 */ 216 void setLine(int l) { 217 if (PARSER_DEBUG) System.out.println("setLine(" + l + ")"); 218 line_num = l; 219 } 220 221 /** 222 * called by the .inner directive 223 */ 224 void addInner(short iacc, String name, String inner, String outer) { 225 throw new IllegalStateException(".inner is not implemented"); 226 } 227 228 /* 229 * ======================================================================== 230 * === FILE HEADER 231 * ======================================================================== 232 */ 233 234 /** 235 * called by the .source directive 236 */ 237 void setSource(String name) { 238 if (PARSER_DEBUG) System.out.println("setSource(" + name + ")"); 239 source_name = name; 240 } 241 242 /** 243 * called by the .bytecode directive 244 */ 245 void setVersion(Number version) { 246 throw new IllegalStateException(".bytecode is not implemented"); 247 } 248 249 /** 250 * called by the .class directive 251 */ 252 void setClass(String name, int acc) { 253 if (PARSER_DEBUG) 254 System.out.println("setClass(" + name + ", " + acc + ")"); 255 class_name = name; 256 class_acc = acc; 257 class_header = true; 258 interfaces.clear(); 259 superclass_name = null; 260 } 261 262 /** 263 * Returns the name of the class in the file (i.e. the string given to the 264 * .class parameter). If there're several classes in one file, returns name 265 * of last class. 266 */ 267 public String getClassName() { 268 return class_name; 269 } 270 271 /** 272 * called by the .super directive 273 */ 274 void setSuperClass(String name) { 275 if (PARSER_DEBUG) System.out.println("setSuperClass(" + name + ")"); 276 superclass_name = name; 277 } 278 279 /** 280 * called by the .implements directive 281 */ 282 void addInterface(String name) { 283 if (PARSER_DEBUG) System.out.println("addInterface(" + name + ")"); 284 285 int sz = interfaces.size(); 286 boolean found = false; 287 // search for duplicates 288 for (int i = 0; i < sz; i++) { 289 String s = interfaces.elementAt(i); 290 if (s.compareTo(name) == 0) { 291 found = true; 292 break; 293 } 294 295 } 296 if (found == false) interfaces.add(name); 297 } 298 299 /** 300 * called by the .signature directive 301 */ 302 void setSignature(String str) throws DasmError { 303 throw new IllegalStateException(".signature is not implemented"); 304 } 305 306 /** 307 * called by the .enclosing directive 308 */ 309 void setEnclosingMethod(String str) { 310 throw new IllegalStateException(".enclosing is not implemented"); 311 } 312 313 /** 314 * called by the .attribute directive 315 */ 316 void addGenericAttr(String name, String file) throws DasmError { 317 throw new IllegalStateException(".attribute is not implemented"); 318 } 319 320 /** 321 * called at end of dasm-header (resolve class variables) 322 */ 323 void endHeader() { 324 325 TypeList tl = createTypeListFromStrings(interfaces); 326 327 classDef = new ClassDefItem(CstType.intern(Type 328 .internClassName(class_name)), class_acc, 329 superclass_name != null ? CstType.intern(Type 330 .internClassName(superclass_name)) : null, tl, 331 new CstString(source_name)); 332 dexFile.add(classDef); 333 class_header = false; 334 } 335 336 /* 337 * ======================================================================== 338 * === FIELDS 339 * ======================================================================== 340 */ 341 342 /** 343 * called by the .field directive to begin 'prompted' field 344 */ 345 void beginField(short access, String name, String desc, Object value) 346 throws DasmError { 347 throw new IllegalStateException( 348 "multiline fields are not implemented yet"); 349 } 350 351 /** 352 * called by the .end field directive to end 'prompted' field 353 */ 354 void endField() throws DasmError { 355 throw new IllegalStateException( 356 "multiline fields are not implemented yet"); 357 } 358 359 /** 360 * called by the .field directive 361 */ 362 void addField(short access, String name, String desc, String sig, 363 Object value) throws DasmError { 364 if (PARSER_DEBUG) 365 System.out.println("addField(" + name + ", " + desc + ", " + sig 366 + ", " + access + ", " 367 + (value == null ? "null" : value.toString()) + ")"); 368 369 CstNat nat = new CstNat(new CstString(name), new CstString(desc)); 370 CstFieldRef field = new CstFieldRef(classDef.getThisClass(), nat); 371 EncodedField ef = new EncodedField(field, access); 372 if ((access & AccessFlags.ACC_STATIC) != 0) { 373 // TODO: value? 374 if (value != null) 375 throw new IllegalStateException( 376 "addField: field initialization not implemented yet"); 377 classDef.addStaticField(ef, null); 378 } else 379 classDef.addInstanceField(ef); 380 } 381 382 383 /* 384 * ======================================================================== 385 * === METHODS 386 * ======================================================================== 387 */ 388 389 /** 390 * called by the .method directive to start the definition for a method 391 */ 392 void newMethod(String name, String descriptor, int access) { 393 if (PARSER_DEBUG) 394 System.out.println("newMethod(" + name + ", " + descriptor + ", " 395 + access + ")"); 396 397 output_finisher = null; 398 throw_list.clear(); 399 unprocessed_relative_goto_addr.clear(); 400 labels_table = new Hashtable<String, LabelTableEntry>(); 401 catch_builder = new DasmCatchBuilder(labels_table); 402 current_insn_number = 0; 403 regs_count = 1; 404 405 method_nat = new CstNat(new CstString(name), new CstString(descriptor)); 406 if (method_nat.isClassInit()) access |= AccessFlags.ACC_STATIC; 407 if (method_nat.isInstanceInit()) access |= AccessFlags.ACC_CONSTRUCTOR; 408 409 method_acc = access; 410 } 411 412 /** 413 * called by the .end method directive to end the definition for a method 414 */ 415 void endMethod() throws DasmError { 416 if (PARSER_DEBUG) System.out.println("endMethod()"); 417 418 // add packed-switch, sparse-switch, fill-array-data data blocks at the 419 // end of method 420 int sz = data_blocks.size(); 421 for (int i = 0; i < sz; i++) { 422 addInsn(data_blocks.elementAt(i)); 423 } 424 data_blocks.clear(); 425 426 // check jump targets 427 if (unprocessed_relative_goto_addr.size() != 0) { 428 report_error("Relative forward jump offset too big."); 429 } 430 Enumeration<String> e = labels_table.keys(); 431 while (e.hasMoreElements()) { 432 String key = e.nextElement(); 433 LabelTableEntry lte = labels_table.get(key); 434 if (lte.planted == false) { 435 report_error("Label " + key + " not found."); 436 } 437 } 438 439 TypeList tl = createTypeListFromStrings(throw_list); 440 441 CstMethodRef meth = new CstMethodRef(classDef.getThisClass(), 442 method_nat); 443 DalvCode code = null; 444 // output_finisher may be null at this point if method is native 445 if (output_finisher != null) 446 code = new DalvCode(PositionList.NONE, output_finisher, 447 catch_builder); 448 enc_method = new EncodedMethod(meth, method_acc, code, tl); 449 450 if (meth.isInstanceInit() || meth.isClassInit() 451 || (method_acc & AccessFlags.ACC_STATIC) != 0 452 || (method_acc & AccessFlags.ACC_PRIVATE) != 0) { 453 classDef.addDirectMethod(enc_method); 454 } else { 455 classDef.addVirtualMethod(enc_method); 456 } 457 catch_builder = null; 458 labels_table = null; 459 } 460 461 /** 462 * used by the .limit regs directive 463 */ 464 void setRegsSize(int v) throws DasmError { 465 if (PARSER_DEBUG) System.out.println("setRegsSize(" + v + ")"); 466 regs_count = v; 467 } 468 469 /** 470 * used by the .throws directive 471 */ 472 void addThrow(String name) throws DasmError { 473 if (PARSER_DEBUG) System.out.println("addThrow(" + name + ")"); 474 throw_list.add(name); 475 } 476 477 /** 478 * used by the .catch directive 479 */ 480 void addCatch(String name, String start_lab, String end_lab, 481 String branch_lab) throws DasmError { 482 if (PARSER_DEBUG) 483 System.out.println("addCatch(" + name + ", " + start_lab + ", " 484 + end_lab + ", " + branch_lab + ")"); 485 catch_builder.add(name, start_lab, end_lab, branch_lab); 486 } 487 488 void addCatch(String name, int start_off, int end_off, int branch_off) 489 throws DasmError { 490 if (PARSER_DEBUG) 491 System.out.println("addCatch(" + name + ", " + start_off + ", " 492 + end_off + ", " + branch_off + ")"); 493 throw new IllegalStateException( 494 "addCatch(String, int, int, int) is not implemented yet"); 495 } 496 497 498 /** 499 * defines a label 500 */ 501 void plantLabel(String name) throws DasmError { 502 if (PARSER_DEBUG) System.out.println("plantLabel(" + name + ")"); 503 createOutputFinisher(); 504 LabelTableEntry lte = labels_table.get(name); 505 if (lte != null) { 506 if (lte.planted == true) 507 report_error("Label " + name + " already defined"); 508 else { 509 lte.planted = true; 510 addInsn(lte.code_address); 511 } 512 } else { 513 CodeAddress code_address = new CodeAddress(createSourcePosition()); 514 addInsn(code_address); 515 labels_table.put(name, new LabelTableEntry(code_address, true)); 516 } 517 } 518 519 520 /** 521 * used for instructions that take no arguments Format: 10x 522 */ 523 void addOpcode(String name) throws DasmError { 524 if (PARSER_DEBUG) System.out.println("addOpcode(" + name + ")"); 525 createOutputFinisher(); 526 DopInfo insn = DopInfo.get(name); 527 if (insn.args.equals("")) { 528 DalvInsn dalvInsn = new SimpleInsn(insn.opcode, 529 createSourcePosition(), RegisterSpecList.EMPTY); 530 addInsn(dalvInsn); 531 } else { 532 throwDasmError("Missing arguments for instruction " + name); 533 } 534 } 535 536 /** 537 * used for instructions that take a word as a parameter (register name is 538 * treated as word) Format: 11x, 10t, 20t, 30t 539 */ 540 void addOpcode(String name, String val) throws DasmError { 541 if (PARSER_DEBUG) 542 System.out.println("addOpcode(" + name + ", " + val + ")"); 543 createOutputFinisher(); 544 DopInfo insn = DopInfo.get(name); 545 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGISTER) == 0) { 546 int reg_num = -1; 547 548 try { 549 reg_num = getRegNumberFromString(val); 550 } catch (IllegalArgumentException e) { 551 throwDasmError("Bad arguments for instruction " + name + "(" 552 + val + ")"); 553 } 554 // TODO: is Type.INT suitable for any opcodes? Or it should be 555 // Type.OBJECT for return-object, for example? 556 RegisterSpec reg_spec = RegisterSpec.make(reg_num, Type.INT); 557 DalvInsn dalvInsn = new SimpleInsn(insn.opcode, 558 createSourcePosition(), RegisterSpecList.make(reg_spec)); 559 addInsn(dalvInsn); 560 } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_ADDRESS) == 0) { 561 LabelTableEntry lte = labels_table.get(val); 562 if (lte == null) { 563 CodeAddress code_address = new CodeAddress( 564 SourcePosition.NO_INFO); 565 lte = new LabelTableEntry(code_address, false); 566 labels_table.put(val, lte); 567 } 568 DalvInsn dalvInsn = new TargetInsn(insn.opcode, 569 createSourcePosition(), RegisterSpecList.EMPTY, 570 lte.code_address); 571 addInsn(dalvInsn); 572 } else { 573 throwDasmError("Bad arguments for instruction " + name + "(" + val 574 + ")"); 575 } 576 } 577 578 /** 579 * used for relative branch targets (ie $+5, $-12, ...) Format: relative 580 * 10t, 20t, 30t 581 */ 582 void addRelativeGoto(String name, int val) throws DasmError { 583 if (PARSER_DEBUG) 584 System.out.println("addRelativeGoto(" + name + ", " + val + ")"); 585 createOutputFinisher(); 586 DopInfo insn = DopInfo.get(name); 587 if (insn.args.compareToIgnoreCase(DopInfo.ARG_ADDRESS) == 0) { 588 if (val == 0) 589 throwDasmError("Bad arguments for instruction " + name + "(" 590 + val + ")"); 591 592 CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO); 593 if (val < 0) { 594 output_finisher.insert(current_insn_number + val, code_address); 595 current_insn_number++; 596 } else { 597 unprocessed_relative_goto_addr.put(current_insn_number + val, 598 code_address); 599 } 600 DalvInsn dalvInsn = new TargetInsn(insn.opcode, 601 createSourcePosition(), RegisterSpecList.EMPTY, 602 code_address); 603 addInsn(dalvInsn); 604 605 } else { 606 throwDasmError("Bad arguments for instruction " + name + "(" + val 607 + ")"); 608 } 609 } 610 611 /** 612 * used for instructions that take two word parameters (register name is 613 * treated as word) Format: 12x, 22x, 32x, 21t, 21c (string@, type@), 31c, 614 * 35c, 3rc 615 */ 616 void addOpcode(String name, String v1, String v2) throws DasmError { 617 if (PARSER_DEBUG) 618 System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2 619 + ")"); 620 createOutputFinisher(); 621 DopInfo insn = DopInfo.get(name); 622 623 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG) == 0) { 624 int reg1_num = -1, reg2_num = -1; 625 626 try { 627 reg1_num = getRegNumberFromString(v1); 628 } catch (IllegalArgumentException e) { 629 throwDasmError("Bad arguments for instruction " + name + "(" 630 + v1 + ")"); 631 } 632 633 try { 634 reg2_num = getRegNumberFromString(v2); 635 } catch (IllegalArgumentException e) { 636 throwDasmError("Bad arguments for instruction " + name + "(" 637 + v2 + ")"); 638 } 639 // TODO: is Type.INT suitable for any opcodes? 640 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 641 RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT); 642 DalvInsn dalvInsn = new SimpleInsn(insn.opcode, 643 createSourcePosition(), RegisterSpecList.make(reg1_spec, 644 reg2_spec)); 645 addInsn(dalvInsn); 646 } else if (insn.args.compareToIgnoreCase( 647 DopInfo.ARG_REG_ADDRESS) == 0) { 648 int reg1_num = -1; 649 650 try { 651 reg1_num = getRegNumberFromString(v1); 652 } catch (IllegalArgumentException e) { 653 throwDasmError("Bad arguments for instruction " + name + "(" 654 + v1 + ")"); 655 } 656 657 LabelTableEntry lte = labels_table.get(v2); 658 if (lte == null) { 659 CodeAddress code_address = new CodeAddress( 660 SourcePosition.NO_INFO); 661 lte = new LabelTableEntry(code_address, false); 662 labels_table.put(v2, lte); 663 } 664 665 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 666 DalvInsn dalvInsn = new TargetInsn(insn.opcode, 667 createSourcePosition(), RegisterSpecList.make(reg1_spec), 668 lte.code_address); 669 addInsn(dalvInsn); 670 } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_STRING) == 0) { 671 int reg1_num = -1; 672 673 try { 674 reg1_num = getRegNumberFromString(v1); 675 } catch (IllegalArgumentException e) { 676 throwDasmError("Bad arguments for instruction " + name + "(" 677 + v1 + ")"); 678 } 679 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.STRING); 680 Constant constant = new CstString(v2); 681 DalvInsn dalvInsn = new CstInsn(insn.opcode, 682 createSourcePosition(), RegisterSpecList.make(reg1_spec), 683 constant); 684 addInsn(dalvInsn); 685 } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_TYPE) == 0) { 686 int reg1_num = -1; 687 688 try { 689 reg1_num = getRegNumberFromString(v1); 690 } catch (IllegalArgumentException e) { 691 throwDasmError("Bad arguments for instruction " + name + "(" 692 + v1 + ")"); 693 } 694 Type type; 695 try { 696 // try to intern it as primitive type first 697 type = Type.intern(v2); 698 } catch (IllegalArgumentException e) { 699 type = Type.internClassName(v2); 700 } 701 702 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, type); 703 Constant constant = CstType.intern(type); 704 DalvInsn dalvInsn = new CstInsn(insn.opcode, 705 createSourcePosition(), RegisterSpecList.make(reg1_spec), 706 constant); 707 addInsn(dalvInsn); 708 } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGLIST_TYPE) == 0 709 || insn.args.compareToIgnoreCase( 710 DopInfo.ARG_REGLIST_METHOD) == 0 711 || insn.args.compareToIgnoreCase( 712 DopInfo.ARG_REGLIST_INTFMETHOD) == 0) { 713 RegisterSpecList reg_spec_list = RegisterSpecList.EMPTY; 714 String regs[] = Utils.splitRegList(v1); 715 if (regs != null) { 716 int rn = regs.length; 717 if (rn == 0 || rn > 5) 718 throwDasmError("Bad arguments for instruction " + name 719 + "(" + v1 + ")"); 720 int reg_num[] = new int[rn]; 721 722 reg_spec_list = new RegisterSpecList(rn); 723 724 for (int i = 0; i < rn; i++) { 725 try { 726 reg_num[i] = getRegNumberFromString(regs[i]); 727 } catch (IllegalArgumentException e) { 728 throwDasmError("Bad arguments for instruction " + name 729 + "(" + v1 + ")"); 730 } 731 reg_spec_list.set(i, RegisterSpec 732 .make(reg_num[i], Type.INT)); 733 } 734 } 735 Constant constant; 736 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGLIST_TYPE) == 0) { 737 // filled-new-array 738 Type type; 739 try { 740 type = Type.intern(v2); 741 } catch (IllegalArgumentException e) { 742 // in case of exception, try to intern type as a class name 743 // (Lclass_name;) 744 type = Type.internClassName(v2); 745 } 746 constant = CstType.intern(type); 747 } else { 748 // invoke-kind 749 String[] names = Utils.getClassMethodSignatureFromString(v2); 750 CstNat method_nat = new CstNat(new CstString(names[1]), 751 new CstString(names[2])); 752 753 /* 754 * if(insn.args.compareToIgnoreCase( 755 * DopInfo.ARG_REGLIST_INTFMETHOD 756 * ) == 0) constant = new 757 * CstInterfaceMethodRef(CstType.intern(Type 758 * .internClassName(names[0])), method_nat); else 759 */ 760 constant = new CstMethodRef(CstType.intern(Type 761 .internClassName(names[0])), method_nat); 762 } 763 764 DalvInsn dalvInsn = new CstInsn(insn.opcode, 765 createSourcePosition(), reg_spec_list, constant); 766 addInsn(dalvInsn); 767 768 } else if (insn.args.compareToIgnoreCase( 769 DopInfo.ARG_REGRANGE_TYPE) == 0 770 || insn.args.compareToIgnoreCase( 771 DopInfo.ARG_REGRANGE_METHOD) == 0 772 || insn.args.compareToIgnoreCase( 773 DopInfo.ARG_REGRANGE_INTFMETHOD) == 0) { 774 String regs[] = Utils.splitRegList(v1); 775 RegisterSpecList reg_spec_list; 776 if (regs != null && regs.length > 0) { 777 int regC = -1, regN = -1; 778 try { 779 regC = getRegNumberFromString(regs[0]); 780 } catch (IllegalArgumentException e) { 781 throwDasmError("Bad arguments for instruction " + name 782 + "(" + v1 + ")"); 783 } 784 785 if (regs.length > 1) { 786 try { 787 regN = getRegNumberFromString(regs[1]); 788 } catch (IllegalArgumentException e) { 789 throwDasmError("Bad arguments for instruction " + name 790 + "(" + v1 + ")"); 791 } 792 793 if (regC >= regN) 794 throwDasmError("Bad arguments for instruction " + name 795 + "(" + v1 + ")"); 796 } else 797 regN = regC; 798 799 800 int sz = regN - regC + 1; 801 reg_spec_list = new RegisterSpecList(sz); 802 803 for (int i = 0; i < sz; i++) { 804 reg_spec_list.set(i, RegisterSpec.make(regC + i, Type.INT)); 805 } 806 } else 807 reg_spec_list = RegisterSpecList.EMPTY; 808 809 Constant constant; 810 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REGRANGE_TYPE) == 0) { 811 // filled-new-array/range 812 Type type; 813 try { 814 type = Type.intern(v2); 815 } catch (IllegalArgumentException e) { 816 // in case of exception, try to intern type as a class name 817 // (Lclass_name;) 818 type = Type.internClassName(v2); 819 } 820 constant = CstType.intern(type); 821 } else { 822 // invoke-kind/range 823 String[] names = Utils.getClassMethodSignatureFromString(v2); 824 CstNat method_nat = new CstNat(new CstString(names[1]), 825 new CstString(names[2])); 826 827 /* 828 * if(insn.args.compareToIgnoreCase( 829 * DopInfo.ARG_REGRANGE_INTFMETHOD 830 * ) == 0) constant = new 831 * CstInterfaceMethodRef(CstType.intern(Type 832 * .internClassName(names[0])), method_nat); else 833 */ 834 constant = new CstMethodRef(CstType.intern(Type 835 .internClassName(names[0])), method_nat); 836 } 837 838 DalvInsn dalvInsn = new CstInsn(insn.opcode, 839 createSourcePosition(), reg_spec_list, constant); 840 addInsn(dalvInsn); 841 842 } else { 843 throwDasmError("Bad arguments for instruction " + name + "(" + v1 844 + ", " + v2 + ")"); 845 } 846 } 847 848 /** 849 * used for relative branch targets (ie $+5, $-12, ...) Format: relative 21t 850 */ 851 void addRelativeGoto(String name, String v1, int val) throws DasmError { 852 if (PARSER_DEBUG) 853 System.out.println("addRelativeGoto(" + name + ", " + v1 + ", " 854 + val + ")"); 855 createOutputFinisher(); 856 DopInfo insn = DopInfo.get(name); 857 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_ADDRESS) == 0) { 858 if (val == 0) 859 throwDasmError("Bad arguments for instruction " + name + "(" 860 + val + ")"); 861 862 int reg1_num = -1; 863 try { 864 reg1_num = getRegNumberFromString(v1); 865 } catch (IllegalArgumentException e) { 866 throwDasmError("Bad arguments for instruction " + name + "(" 867 + v1 + ")"); 868 } 869 870 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 871 RegisterSpecList rsl = RegisterSpecList.make(reg1_spec); 872 CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO); 873 if (val < 0) { 874 output_finisher.insert(current_insn_number + val, code_address); 875 current_insn_number++; 876 } else { 877 unprocessed_relative_goto_addr.put(current_insn_number + val, 878 code_address); 879 } 880 DalvInsn dalvInsn = new TargetInsn(insn.opcode, 881 createSourcePosition(), rsl, code_address); 882 addInsn(dalvInsn); 883 884 } else { 885 throwDasmError("Bad arguments for instruction " + name + "(" + val 886 + ")"); 887 } 888 } 889 890 /** 891 * used for instructions that take one word parameter (register name is 892 * treated as word) and one literal Format: 11n, 21s, 31i, 21h, 51l 893 */ 894 void addOpcode(String name, String v1, Number v2) throws DasmError { 895 if (PARSER_DEBUG) 896 System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2 897 + ")"); 898 createOutputFinisher(); 899 DopInfo insn = DopInfo.get(name); 900 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_LITERAL) == 0) { 901 int reg1_num = -1; 902 903 try { 904 reg1_num = getRegNumberFromString(v1); 905 } catch (IllegalArgumentException e) { 906 throwDasmError("Bad arguments for instruction " + name + "(" 907 + v1 + ")"); 908 } 909 910 RegisterSpec reg1_spec; 911 Constant constant; 912 // create Constant of type suitable for value specified in 913 // instruction 914 if (v2 instanceof Long 915 || (v2 instanceof Integer && 916 insn.opcode.getFormat() == Form51l.THE_ONE)) { 917 reg1_spec = RegisterSpec.make(reg1_num, Type.LONG); 918 constant = CstLong.make(v2.longValue()); 919 } else if (v2 instanceof Float 920 && insn.opcode.getFormat() != Form51l.THE_ONE) { 921 reg1_spec = RegisterSpec.make(reg1_num, Type.FLOAT); 922 constant = CstFloat.make(Float.floatToIntBits(v2.floatValue())); 923 } else if (v2 instanceof Double 924 || (v2 instanceof Float && 925 insn.opcode.getFormat() == Form51l.THE_ONE)) { 926 reg1_spec = RegisterSpec.make(reg1_num, Type.DOUBLE); 927 constant = CstDouble.make(Double.doubleToLongBits(v2 928 .doubleValue())); 929 } else { 930 reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 931 constant = CstInteger.make(v2.intValue()); 932 } 933 934 DalvInsn dalvInsn = new CstInsn(insn.opcode, 935 createSourcePosition(), RegisterSpecList.make(reg1_spec), 936 constant); 937 addInsn(dalvInsn); 938 } else { 939 throwDasmError("Bad arguments for instruction " + name + "(" + v1 940 + ", " + v2 + ")"); 941 } 942 943 } 944 945 /** 946 * used for instructions that take three word parameters (register name is 947 * treated as word) Format: 23x, 22t, 21c (field@), 22c (type@) 948 */ 949 void addOpcode(String name, String v1, String v2, String v3) 950 throws DasmError { 951 if (PARSER_DEBUG) 952 System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2 953 + ", " + v3 + ")"); 954 createOutputFinisher(); 955 DopInfo insn = DopInfo.get(name); 956 957 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_REG) == 0) { 958 int reg1_num = -1, reg2_num = -1, reg3_num = -1; 959 960 try { 961 reg1_num = getRegNumberFromString(v1); 962 } catch (IllegalArgumentException e) { 963 throwDasmError("Bad arguments for instruction " + name + "(" 964 + v1 + ")"); 965 } 966 967 try { 968 reg2_num = getRegNumberFromString(v2); 969 } catch (IllegalArgumentException e) { 970 throwDasmError("Bad arguments for instruction " + name + "(" 971 + v2 + ")"); 972 } 973 974 try { 975 reg3_num = getRegNumberFromString(v3); 976 } catch (IllegalArgumentException e) { 977 throwDasmError("Bad arguments for instruction " + name + "(" 978 + v3 + ")"); 979 } 980 // TODO: is Type.INT suitable for any opcodes? 981 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 982 RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT); 983 RegisterSpec reg3_spec = RegisterSpec.make(reg3_num, Type.INT); 984 DalvInsn dalvInsn = new SimpleInsn(insn.opcode, 985 createSourcePosition(), RegisterSpecList.make(reg1_spec, 986 reg2_spec, reg3_spec)); 987 addInsn(dalvInsn); 988 } else if (insn.args.compareToIgnoreCase( 989 DopInfo.ARG_REG_REG_ADDRESS) == 0) { 990 int reg1_num = -1, reg2_num = -1; 991 992 try { 993 reg1_num = getRegNumberFromString(v1); 994 } catch (IllegalArgumentException e) { 995 throwDasmError("Bad arguments for instruction " + name + "(" 996 + v1 + ")"); 997 } 998 999 try { 1000 reg2_num = getRegNumberFromString(v2); 1001 } catch (IllegalArgumentException e) { 1002 throwDasmError("Bad arguments for instruction " + name + "(" 1003 + v2 + ")"); 1004 } 1005 1006 LabelTableEntry lte = labels_table.get(v3); 1007 if (lte == null) { 1008 CodeAddress code_address = new CodeAddress( 1009 SourcePosition.NO_INFO); 1010 lte = new LabelTableEntry(code_address, false); 1011 labels_table.put(v3, lte); 1012 } 1013 1014 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 1015 RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT); 1016 1017 DalvInsn dalvInsn = new TargetInsn(insn.opcode, 1018 createSourcePosition(), RegisterSpecList.make(reg1_spec, 1019 reg2_spec), lte.code_address); 1020 addInsn(dalvInsn); 1021 } else if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_FIELD) == 0) { 1022 int reg1_num = -1; 1023 1024 try { 1025 reg1_num = getRegNumberFromString(v1); 1026 } catch (IllegalArgumentException e) { 1027 throwDasmError("Bad arguments for instruction " + name + "(" 1028 + v1 + ")"); 1029 } 1030 // TODO: is Type.INT suitable? 1031 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 1032 1033 String[] names = Utils.getClassFieldFromString(v2); 1034 1035 CstNat field_nat = new CstNat(new CstString(names[1]), 1036 new CstString(v3)); 1037 1038 Constant constant = new CstFieldRef(CstType.intern(Type 1039 .internClassName(names[0])), field_nat); 1040 DalvInsn dalvInsn = new CstInsn(insn.opcode, 1041 createSourcePosition(), RegisterSpecList.make(reg1_spec), 1042 constant); 1043 addInsn(dalvInsn); 1044 } else if (insn.args.compareToIgnoreCase( 1045 DopInfo.ARG_REG_REG_TYPE) == 0) { 1046 int reg1_num = -1, reg2_num = -1; 1047 1048 try { 1049 reg1_num = getRegNumberFromString(v1); 1050 } catch (IllegalArgumentException e) { 1051 throwDasmError("Bad arguments for instruction " + name + "(" 1052 + v1 + ")"); 1053 } 1054 1055 try { 1056 reg2_num = getRegNumberFromString(v2); 1057 } catch (IllegalArgumentException e) { 1058 throwDasmError("Bad arguments for instruction " + name + "(" 1059 + v2 + ")"); 1060 } 1061 1062 Type type = Type.internClassName(v3); 1063 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, type); 1064 RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, type); 1065 Constant constant = CstType.intern(type); 1066 DalvInsn dalvInsn = new CstInsn(insn.opcode, 1067 createSourcePosition(), RegisterSpecList.make(reg1_spec, 1068 reg2_spec), constant); 1069 addInsn(dalvInsn); 1070 } else { 1071 throwDasmError("Bad arguments for instruction " + name + "(" + v1 1072 + ", " + v2 + ", " + v3 + ")"); 1073 } 1074 } 1075 1076 /** 1077 * Format: 22c (field@) 1078 */ 1079 void addOpcode(String name, String v1, String v2, String v3, String v4) 1080 throws DasmError { 1081 if (PARSER_DEBUG) 1082 System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2 1083 + ", " + v3 + ", " + v4 + ")"); 1084 createOutputFinisher(); 1085 DopInfo insn = DopInfo.get(name); 1086 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_FIELD) == 0) { 1087 int reg1_num = -1, reg2_num = -1; 1088 1089 try { 1090 reg1_num = getRegNumberFromString(v1); 1091 } catch (IllegalArgumentException e) { 1092 throwDasmError("Bad arguments for instruction " + name + "(" 1093 + v1 + ")"); 1094 } 1095 try { 1096 reg2_num = getRegNumberFromString(v2); 1097 } catch (IllegalArgumentException e) { 1098 throwDasmError("Bad arguments for instruction " + name + "(" 1099 + v2 + ")"); 1100 } 1101 // TODO: is Type.INT suitable? 1102 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 1103 RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT); 1104 1105 String[] names = Utils.getClassFieldFromString(v3); 1106 1107 CstNat field_nat = new CstNat(new CstString(names[1]), 1108 new CstString(v4)); 1109 1110 Constant constant = new CstFieldRef(CstType.intern(Type 1111 .internClassName(names[0])), field_nat); 1112 DalvInsn dalvInsn = new CstInsn(insn.opcode, 1113 createSourcePosition(), RegisterSpecList.make(reg1_spec, 1114 reg2_spec), constant); 1115 addInsn(dalvInsn); 1116 } else if (insn.args.compareToIgnoreCase( 1117 DopInfo.ARG_REGRANGE_TYPE) == 0) { 1118 String regs[] = Utils.splitRegList(v1); 1119 if (regs.length != 2) 1120 throwDasmError("Bad arguments for instruction " + name + "(" 1121 + v1 + ")"); 1122 1123 int regC = -1, regN = -1; 1124 try { 1125 regC = getRegNumberFromString(regs[0]); 1126 } catch (IllegalArgumentException e) { 1127 throwDasmError("Bad arguments for instruction " + name + "(" 1128 + v1 + ")"); 1129 } 1130 try { 1131 regN = getRegNumberFromString(regs[1]); 1132 } catch (IllegalArgumentException e) { 1133 throwDasmError("Bad arguments for instruction " + name + "(" 1134 + v1 + ")"); 1135 } 1136 1137 if (regC >= regN) 1138 throwDasmError("Bad arguments for instruction " + name + "(" 1139 + v1 + ")"); 1140 1141 int sz = regN - regC + 1; 1142 RegisterSpecList reg_spec_list = new RegisterSpecList(sz); 1143 1144 for (int i = 0; i < sz; i++) { 1145 reg_spec_list.set(i, RegisterSpec.make(regC + i, Type.INT)); 1146 } 1147 1148 Type type; 1149 try { 1150 type = Type.intern(v2); 1151 } catch (IllegalArgumentException e) { 1152 // in case of exception, try to intern type as a class name 1153 // (Lclass_name;) 1154 type = Type.internClassName(v2); 1155 } 1156 Constant constant = CstType.intern(type); 1157 1158 DalvInsn dalvInsn = new CstInsn(insn.opcode, 1159 createSourcePosition(), reg_spec_list, constant); 1160 addInsn(dalvInsn); 1161 1162 } else { 1163 throwDasmError("Bad arguments for instruction " + name + "(" + v1 1164 + ", " + v2 + ", " + v3 + ", " + v4 + ")"); 1165 } 1166 } 1167 1168 /** 1169 * used for relative branch targets (ie $+5, $-12, ...) Format: relative 22t 1170 */ 1171 void addRelativeGoto(String name, String v1, String v2, int val) 1172 throws DasmError { 1173 if (PARSER_DEBUG) 1174 System.out.println("addRelativeGoto(" + name + ", " + v1 + ", " 1175 + v2 + ", " + val + ")"); 1176 createOutputFinisher(); 1177 DopInfo insn = DopInfo.get(name); 1178 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_ADDRESS) == 0) { 1179 if (val == 0) 1180 throwDasmError("Bad arguments for instruction " + name + "(" 1181 + val + ")"); 1182 1183 int reg1_num = -1, reg2_num = -1; 1184 1185 try { 1186 reg1_num = getRegNumberFromString(v1); 1187 } catch (IllegalArgumentException e) { 1188 throwDasmError("Bad arguments for instruction " + name + "(" 1189 + v1 + ")"); 1190 } 1191 1192 try { 1193 reg2_num = getRegNumberFromString(v2); 1194 } catch (IllegalArgumentException e) { 1195 throwDasmError("Bad arguments for instruction " + name + "(" 1196 + v2 + ")"); 1197 } 1198 1199 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 1200 RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT); 1201 RegisterSpecList rsl = RegisterSpecList.make(reg1_spec, reg2_spec); 1202 CodeAddress code_address = new CodeAddress(SourcePosition.NO_INFO); 1203 if (val < 0) { 1204 output_finisher.insert(current_insn_number + val, code_address); 1205 current_insn_number++; 1206 } else { 1207 unprocessed_relative_goto_addr.put(current_insn_number + val, 1208 code_address); 1209 } 1210 DalvInsn dalvInsn = new TargetInsn(insn.opcode, 1211 createSourcePosition(), rsl, code_address); 1212 addInsn(dalvInsn); 1213 1214 } else { 1215 throwDasmError("Bad arguments for instruction " + name + "(" + val 1216 + ")"); 1217 } 1218 } 1219 1220 /** 1221 * used for instructions that take two word parameters (register name is 1222 * treated as word) and one literal Format: 22b, 22s 1223 */ 1224 void addOpcode(String name, String v1, String v2, int v3) throws DasmError { 1225 if (PARSER_DEBUG) 1226 System.out.println("addOpcode(" + name + ", " + v1 + ", " + v2 1227 + ")"); 1228 createOutputFinisher(); 1229 DopInfo insn = DopInfo.get(name); 1230 1231 if (insn.args.compareToIgnoreCase(DopInfo.ARG_REG_REG_LITERAL) == 0) { 1232 int reg1_num = -1, reg2_num = -1; 1233 1234 try { 1235 reg1_num = getRegNumberFromString(v1); 1236 } catch (IllegalArgumentException e) { 1237 throwDasmError("Bad arguments for instruction " + name + "(" 1238 + v1 + ")"); 1239 } 1240 1241 try { 1242 reg2_num = getRegNumberFromString(v2); 1243 } catch (IllegalArgumentException e) { 1244 throwDasmError("Bad arguments for instruction " + name + "(" 1245 + v2 + ")"); 1246 } 1247 // TODO: is Type.INT suitable for any opcodes? 1248 RegisterSpec reg1_spec = RegisterSpec.make(reg1_num, Type.INT); 1249 RegisterSpec reg2_spec = RegisterSpec.make(reg2_num, Type.INT); 1250 Constant constant = CstInteger.make(v3); 1251 DalvInsn dalvInsn = new CstInsn(insn.opcode, 1252 createSourcePosition(), RegisterSpecList.make(reg1_spec, 1253 reg2_spec), constant); 1254 addInsn(dalvInsn); 1255 } else { 1256 throwDasmError("Bad arguments for instruction " + name + "(" + v1 1257 + ", " + v2 + ", " + v3 + ")"); 1258 } 1259 } 1260 1261 /** 1262 * used for fill-array-data instruction Format: 31t fill-array-data 1263 * instruction has the syntax: fill-array-data <register> <type> 1264 * <value1> <value2> .... fill-array-data-end For example: 1265 * fill-array-data v7 I 1 2 3 4 5 fill-array-data-end 1266 */ 1267 void newFillArrayData(String reg, String type) throws DasmError { 1268 if (PARSER_DEBUG) 1269 System.out.println("newFillArrayData(" + reg + ", " + type + ")"); 1270 1271 try { 1272 fill_data_reg = getRegNumberFromString(reg); 1273 } catch (IllegalArgumentException e) { 1274 throwDasmError("Bad arguments for fill-array-data (" + reg + ")"); 1275 } 1276 1277 fill_array_data_type = type; 1278 fill_array_data_values = new Vector<Number>(); 1279 } 1280 1281 /** 1282 * add new value to data block 1283 */ 1284 void addFillArrayData(Number num) throws DasmError { 1285 if (PARSER_DEBUG) System.out.println("addFillArrayData(" + num + ")"); 1286 fill_array_data_values.add(num); 1287 } 1288 1289 /** 1290 * called by fill-array-data-end 1291 */ 1292 void endFillArrayData() throws DasmError { 1293 if (PARSER_DEBUG) System.out.println("endFillArrayData"); 1294 int sz = fill_array_data_values.size(); 1295 ArrayList<Constant> values = new ArrayList<Constant>(sz); 1296 CstType arrayType = CstType.intern(Type.intern("[" 1297 + fill_array_data_type)); 1298 for (int i = 0; i < sz; i++) { 1299 Constant constant; 1300 Number num = fill_array_data_values.elementAt(i); 1301 if (arrayType == CstType.LONG_ARRAY) { 1302 constant = CstLong.make(num.longValue()); 1303 } else if (arrayType == CstType.FLOAT_ARRAY) { 1304 constant = CstFloat 1305 .make(Float.floatToIntBits(num.floatValue())); 1306 } else if (arrayType == CstType.DOUBLE_ARRAY) { 1307 constant = CstDouble.make(Double.doubleToLongBits(num 1308 .doubleValue())); 1309 } else if (arrayType == CstType.BOOLEAN_ARRAY) { 1310 constant = CstBoolean.make(num.intValue()); 1311 } else if (arrayType == CstType.BYTE_ARRAY) { 1312 constant = CstByte.make(num.intValue()); 1313 } else if (arrayType == CstType.CHAR_ARRAY) { 1314 constant = CstChar.make(num.intValue()); 1315 } else if (arrayType == CstType.SHORT_ARRAY) { 1316 constant = CstShort.make(num.intValue()); 1317 } else { 1318 constant = CstInteger.make(num.intValue()); 1319 } 1320 values.add(constant); 1321 } 1322 1323 CodeAddress insn_addr = new CodeAddress(createSourcePosition()); 1324 CodeAddress data_addr = new CodeAddress(SourcePosition.NO_INFO); 1325 DalvInsn dalvInsn = new TargetInsn(Dops.FILL_ARRAY_DATA, 1326 createSourcePosition(), RegisterSpecList 1327 .make(RegisterSpec.make(fill_data_reg, Type 1328 .intern(fill_array_data_type))), data_addr); 1329 OddSpacer spacer = new OddSpacer(SourcePosition.NO_INFO); 1330 ArrayData array_data = new ArrayData(SourcePosition.NO_INFO, insn_addr, 1331 values, arrayType); 1332 1333 addInsn(insn_addr); 1334 addInsn(dalvInsn); 1335 data_blocks.add(spacer); 1336 data_blocks.add(data_addr); 1337 data_blocks.add(array_data); 1338 1339 fill_array_data_values = null; 1340 fill_array_data_type = null; 1341 } 1342 1343 /** 1344 * used for packed-switch instruction Format: 31t packed-switch instruction 1345 * has the syntax: packed-switch <register> <lowest> 1346 * <label1> <label2> .... packed-switch-end For example: 1347 * packed-switch v3, -1 Label9 Label6 Label6 Label12 Label12 1348 * packed-switch-end 1349 */ 1350 void newPackedSwitch(String reg, int first_key) throws DasmError { 1351 if (PARSER_DEBUG) 1352 System.out.println("newPackedSwitch(" + reg + ", " + first_key 1353 + ")"); 1354 1355 try { 1356 switch_reg = getRegNumberFromString(reg); 1357 } catch (IllegalArgumentException e) { 1358 throwDasmError("Bad arguments for packed-switch (" + reg + ")"); 1359 } 1360 1361 packed_switch_first_key = first_key; 1362 packed_switch_current_key = 0; 1363 switch_targets = new Vector<Object>(); 1364 switch_keys = new IntList(); 1365 } 1366 1367 /** 1368 * add new target to packed-switch 1369 */ 1370 void addPackedSwitchData(String target) throws DasmError { 1371 if (PARSER_DEBUG) 1372 System.out.println("addPackedSwitchData(" + target + ")"); 1373 switch_targets.add(target); 1374 switch_keys.add(packed_switch_first_key + packed_switch_current_key); 1375 packed_switch_current_key++; 1376 } 1377 1378 /** 1379 * add new target to packed-switch 1380 */ 1381 void addPackedSwitchData(int target) throws DasmError { 1382 if (PARSER_DEBUG) 1383 System.out.println("addPackedSwitchData(" + target + ")"); 1384 switch_targets.add(new Integer(target)); 1385 switch_keys.add(packed_switch_first_key + packed_switch_current_key); 1386 packed_switch_current_key++; 1387 } 1388 1389 /** 1390 * used for sparse-switch instruction Format: 31t sparse-switch instruction 1391 * has the syntax: sparse-switch <register> <lowest> 1392 * <int1> : <label1> <int2> : <label2> .... 1393 * sparse-switch-end For example: sparse-switch v3 -1 : Label9 10 : Label12 1394 * 15 : Label12 sparse-switch-end 1395 */ 1396 void newSparseSwitch(String reg) throws DasmError { 1397 if (PARSER_DEBUG) System.out.println("newSparseSwitch(" + reg + ")"); 1398 1399 try { 1400 switch_reg = getRegNumberFromString(reg); 1401 } catch (IllegalArgumentException e) { 1402 throwDasmError("Bad arguments for sparse-switch (" + reg + ")"); 1403 } 1404 1405 switch_targets = new Vector<Object>(); 1406 switch_keys = new IntList(); 1407 } 1408 1409 /** 1410 * add new target to sparse-switch 1411 */ 1412 void addSparseSwitchData(int key, String target) throws DasmError { 1413 if (PARSER_DEBUG) 1414 System.out.println("addSparseSwitchData(" + key + ", " + target 1415 + ")"); 1416 switch_targets.add(target); 1417 switch_keys.add(key); 1418 } 1419 1420 /** 1421 * add new target to sparse-switch 1422 */ 1423 void addSparseSwitchData(int key, int target) throws DasmError { 1424 if (PARSER_DEBUG) 1425 System.out.println("addSparseSwitchData(" + key + ", " + target 1426 + ")"); 1427 switch_targets.add(new Integer(target)); 1428 switch_keys.add(key); 1429 } 1430 1431 /** 1432 * called by sparse-switch-end or packed-switch-end 1433 */ 1434 void endSwitch() throws DasmError { 1435 if (PARSER_DEBUG) System.out.println("endSwitch"); 1436 int sz = switch_targets.size(); 1437 1438 CodeAddress targets[] = new CodeAddress[sz]; 1439 for (int i = 0; i < sz; i++) { 1440 Object o = switch_targets.elementAt(i); 1441 CodeAddress addr; 1442 if (o instanceof String) { 1443 String t = (String) o; 1444 LabelTableEntry lte = labels_table.get(t); 1445 if (lte == null) { 1446 CodeAddress code_address = new CodeAddress( 1447 SourcePosition.NO_INFO); 1448 lte = new LabelTableEntry(code_address, false); 1449 labels_table.put(t, lte); 1450 } 1451 addr = lte.code_address; 1452 } else { 1453 Integer t = (Integer) o; 1454 1455 addr = new CodeAddress(SourcePosition.NO_INFO); 1456 if (t < 0) { 1457 output_finisher.insert(current_insn_number + t, addr); 1458 current_insn_number++; 1459 } else { 1460 unprocessed_relative_goto_addr.put(current_insn_number + t, 1461 addr); 1462 } 1463 } 1464 targets[i] = addr; 1465 } 1466 1467 CodeAddress insn_addr = new CodeAddress(createSourcePosition()); 1468 CodeAddress data_addr = new CodeAddress(SourcePosition.NO_INFO); 1469 OddSpacer spacer = new OddSpacer(SourcePosition.NO_INFO); 1470 SwitchData switch_data = new SwitchData(SourcePosition.NO_INFO, 1471 insn_addr, switch_keys, targets); 1472 DalvInsn dalvInsn = new TargetInsn(switch_data.isPacked() 1473 ? Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH, 1474 createSourcePosition(), RegisterSpecList.make(RegisterSpec 1475 .make(switch_reg, Type.INT)), data_addr); 1476 1477 addInsn(insn_addr); 1478 addInsn(dalvInsn); 1479 data_blocks.add(spacer); 1480 data_blocks.add(data_addr); 1481 data_blocks.add(switch_data); 1482 1483 switch_targets = null; 1484 switch_keys = null; 1485 } 1486 1487 /* 1488 * ======================================================================== 1489 * === UTILITY METHODS 1490 * ======================================================================== 1491 */ 1492 1493 /** 1494 * Creates instance of SourcePosition for current line 1495 */ 1496 protected SourcePosition createSourcePosition() { 1497 return new SourcePosition(new CstString(filename), -1, line_num); 1498 } 1499 1500 /** 1501 * Creates TypeList from list of types 1502 */ 1503 protected TypeList createTypeListFromStrings(Vector<String> strings) { 1504 StdTypeList tl; 1505 1506 if (strings.size() == 0) 1507 tl = StdTypeList.EMPTY; 1508 else { 1509 int sz = strings.size(); 1510 tl = new StdTypeList(sz); 1511 for (int i = 0; i < sz; i++) { 1512 tl.set(i, Type.internClassName(strings.elementAt(i))); 1513 } 1514 } 1515 return tl; 1516 } 1517 1518 /** 1519 * Creates processor of instruction list. 1520 */ 1521 private void createOutputFinisher() { 1522 if (output_finisher == null) 1523 output_finisher = new OutputFinisher(dexOptions, 5, regs_count); 1524 } 1525 1526 /** 1527 * Returns register number from "vX" string. 1528 */ 1529 private int getRegNumberFromString(String val) 1530 throws IllegalArgumentException { 1531 int reg_num; 1532 int l = RegisterSpec.PREFIX.length(); 1533 if (val.length() <= l 1534 || val.substring(0, l).compareToIgnoreCase( 1535 RegisterSpec.PREFIX) != 0) 1536 throw new IllegalArgumentException("Wrong register name prefix"); 1537 1538 try { 1539 reg_num = Integer.parseInt(val.substring(l)); 1540 } catch (Exception e) { 1541 throw new IllegalArgumentException("Wrong register name"); 1542 } 1543 return reg_num; 1544 } 1545 1546 /** 1547 * Adds new instruction to instruction list. 1548 */ 1549 private void addInsn(DalvInsn insn) { 1550 createOutputFinisher(); 1551 CodeAddress code_address = unprocessed_relative_goto_addr 1552 .get(current_insn_number); 1553 if (code_address != null) { 1554 output_finisher.add(code_address); 1555 unprocessed_relative_goto_addr.remove(current_insn_number); 1556 current_insn_number++; 1557 } 1558 output_finisher.add(insn); 1559 current_insn_number++; 1560 } 1561 1562 /* 1563 * ======================================================================== 1564 * === READER and WRITER 1565 * ======================================================================== 1566 */ 1567 1568 /** 1569 * Writes the binary data for the class represented by this ClassFile object 1570 * to the specified output stream, using the Java Class File format. Throws 1571 * either an IOException or a dasmError if something goes wrong. 1572 */ 1573 public void write(OutputStream outp, FileWriter human_readable) 1574 throws IOException, DasmError { 1575 dexFile.writeTo(outp, human_readable, true); 1576 } 1577 1578 /** 1579 * Parses a .d file, converting it internally into a binary representation. 1580 * If something goes wrong, this throws one of an IOException, or a 1581 * dasmError, or one of a few other exceptions. 1582 * 1583 * @param input 1584 * is the stream containing the Dalvik assembly code for the 1585 * class. 1586 * @param name 1587 * is the name of the stream. This name will be concatenated to 1588 * error messages printed to System.err. 1589 * @param numberLines 1590 * true if you want DAsm to generate line numbers automatically, 1591 * based on the assembly source, or false if you are using the 1592 * ".line" directive and don't want DAsm to help out. 1593 */ 1594 public void readD(Reader input, String name, boolean numberLines) 1595 throws IOException, Exception { 1596 1597 // TODO: numberLines? 1598 errors = 0; 1599 filename = name; 1600 source_name = name; 1601 class_header = false; 1602 classDef = null; 1603 dexFile = new DexFile(dexOptions); 1604 1605 scanner = new Scanner(input); 1606 parser parse_obj = new parser(this, scanner); 1607 1608 1609 if (PARSER_DEBUG) { 1610 // for debugging 1611 parse_obj.debug_parse(); 1612 } else { 1613 parse_obj.parse(); 1614 } 1615 1616 } 1617 } 1618