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