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