001: /* ===========================================================================
002: * $RCSfile: CodeAttrInfo.java,v $
003: * ===========================================================================
004: *
005: * RetroGuard -- an obfuscation package for Java classfiles.
006: *
007: * Copyright (c) 1998-2006 Mark Welsh (markw@retrologic.com)
008: *
009: * This program can be redistributed and/or modified under the terms of the
010: * Version 2 of the GNU General Public License as published by the Free
011: * Software Foundation.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: */
019:
020: package COM.rl.obf.classfile;
021:
022: import java.io.*;
023: import java.util.*;
024: import COM.rl.util.*;
025:
026: /**
027: * Representation of an attribute.
028: *
029: * @author Mark Welsh
030: */
031: public class CodeAttrInfo extends AttrInfo {
032: // Constants -------------------------------------------------------------
033: public static final int CONSTANT_FIELD_SIZE = 12;
034:
035: // Fields ----------------------------------------------------------------
036: private int u2maxStack;
037: private int u2maxLocals;
038: private int u4codeLength;
039: private byte[] code;
040: private int u2exceptionTableLength;
041: private ExceptionInfo[] exceptionTable;
042: protected int u2attributesCount;
043: protected AttrInfo[] attributes;
044:
045: // Class Methods ---------------------------------------------------------
046: // Number of bytes following an opcode
047: private static int opcodeBytes(int opcode) {
048: switch (opcode) {
049: case 0xAA:
050: case 0xAB:
051: case 0xC4:
052: return -1; // variable length opcode
053: case 0x10:
054: case 0x12:
055: case 0x15:
056: case 0x16:
057: case 0x17:
058: case 0x18:
059: case 0x19:
060: case 0x36:
061: case 0x37:
062: case 0x38:
063: case 0x39:
064: case 0x3A:
065: case 0xBC:
066: return 1;
067: case 0x11:
068: case 0x13:
069: case 0x14:
070: case 0x84:
071: case 0x99:
072: case 0x9A:
073: case 0x9B:
074: case 0x9C:
075: case 0x9D:
076: case 0x9E:
077: case 0x9F:
078: case 0xA0:
079: case 0xA1:
080: case 0xA2:
081: case 0xA3:
082: case 0xA4:
083: case 0xA5:
084: case 0xA6:
085: case 0xA7:
086: case 0xA8:
087: case 0xB2:
088: case 0xB3:
089: case 0xB4:
090: case 0xB5:
091: case 0xB6:
092: case 0xB7:
093: case 0xB8:
094: case 0xBB:
095: case 0xBD:
096: case 0xC0:
097: case 0xC1:
098: case 0xC6:
099: case 0xC7:
100: return 2;
101: case 0xC5:
102: return 3;
103: case 0xB9:
104: case 0xC8:
105: case 0xC9:
106: return 4;
107: default:
108: return 0;
109: }
110: }
111:
112: // Instance Methods ------------------------------------------------------
113: protected CodeAttrInfo(ClassFile cf, int attrNameIndex,
114: int attrLength) {
115: super (cf, attrNameIndex, attrLength);
116: }
117:
118: /** Return the length in bytes of the attribute. */
119: protected int getAttrInfoLength() throws Exception {
120: int length = CONSTANT_FIELD_SIZE + u4codeLength
121: + u2exceptionTableLength
122: * ExceptionInfo.CONSTANT_FIELD_SIZE;
123: for (int i = 0; i < u2attributesCount; i++) {
124: length += AttrInfo.CONSTANT_FIELD_SIZE
125: + attributes[i].getAttrInfoLength();
126: }
127: return length;
128: }
129:
130: /** Return the String name of the attribute; over-ride this in sub-classes. */
131: protected String getAttrName() throws Exception {
132: return ATTR_Code;
133: }
134:
135: /**
136: * Trim attributes from the classfile ('Code', 'Exceptions', 'ConstantValue'
137: * are preserved, all others except the list in the String[] are killed).
138: */
139: protected void trimAttrsExcept(String[] keepAttrs) throws Exception {
140: // Traverse all attributes, removing all except those on 'keep' list
141: for (int i = 0; i < attributes.length; i++) {
142: if (Tools.isInArray(attributes[i].getAttrName(), keepAttrs)) {
143: attributes[i].trimAttrsExcept(keepAttrs);
144: } else {
145: attributes[i] = null;
146: }
147: }
148:
149: // Delete the marked attributes
150: AttrInfo[] left = new AttrInfo[attributes.length];
151: int j = 0;
152: for (int i = 0; i < attributes.length; i++) {
153: if (attributes[i] != null) {
154: left[j++] = attributes[i];
155: }
156: }
157: attributes = new AttrInfo[j];
158: System.arraycopy(left, 0, attributes, 0, j);
159: u2attributesCount = j;
160: }
161:
162: /** Check for references in the 'info' data to the constant pool and mark them. */
163: protected void markUtf8RefsInInfo(ConstantPool pool)
164: throws Exception {
165: for (int i = 0; i < attributes.length; i++) {
166: attributes[i].markUtf8Refs(pool);
167: }
168: }
169:
170: /** Read the data following the header. */
171: protected void readInfo(DataInput din) throws Exception {
172: u2maxStack = din.readUnsignedShort();
173: u2maxLocals = din.readUnsignedShort();
174: u4codeLength = din.readInt();
175: code = new byte[u4codeLength];
176: din.readFully(code);
177: u2exceptionTableLength = din.readUnsignedShort();
178: exceptionTable = new ExceptionInfo[u2exceptionTableLength];
179: for (int i = 0; i < u2exceptionTableLength; i++) {
180: exceptionTable[i] = ExceptionInfo.create(din);
181: }
182: u2attributesCount = din.readUnsignedShort();
183: attributes = new AttrInfo[u2attributesCount];
184: for (int i = 0; i < u2attributesCount; i++) {
185: attributes[i] = AttrInfo.create(din, cf);
186: }
187: }
188:
189: /** Export data following the header to a DataOutput stream. */
190: public void writeInfo(DataOutput dout) throws Exception {
191: dout.writeShort(u2maxStack);
192: dout.writeShort(u2maxLocals);
193: dout.writeInt(u4codeLength);
194: dout.write(code);
195: dout.writeShort(u2exceptionTableLength);
196: for (int i = 0; i < u2exceptionTableLength; i++) {
197: exceptionTable[i].write(dout);
198: }
199: dout.writeShort(u2attributesCount);
200: for (int i = 0; i < u2attributesCount; i++) {
201: attributes[i].write(dout);
202: }
203: }
204:
205: /** Do necessary name remapping. */
206: protected void remap(ClassFile cf, NameMapper nm) throws Exception {
207: for (int i = 0; i < u2attributesCount; i++) {
208: attributes[i].remap(cf, nm);
209: }
210: }
211:
212: /** Walk the code, finding .class and Class.forName to update. */
213: protected FlagHashtable walkFindClassStrings(FlagHashtable cpToFlag)
214: throws Exception {
215: return walkClassStrings(cpToFlag, null);
216: }
217:
218: /** Walk the code, updating .class and Class.forName strings. */
219: protected void walkUpdateClassStrings(Hashtable cpUpdate)
220: throws Exception {
221: walkClassStrings(null, cpUpdate);
222: }
223:
224: /** Walk the code, updating .class and Class.forName strings. */
225: // Note that class literals MyClass.class are stored directly in the
226: // constant pool in 1.5 (change from 1.4), not referenced by Utf8 name,
227: // so .option MapClassString is not necessary for them.
228: // Still needed for Class.forName("MyClass") though.
229: private FlagHashtable walkClassStrings(FlagHashtable cpToFlag,
230: Hashtable cpUpdate) throws Exception {
231: int opcodePrev = -1;
232: int ldcIndex = -1;
233: for (int i = 0; i < code.length; i++) {
234: int opcode = code[i] & 0xFF;
235: if ((opcode == 0x12) && (i + 1 < code.length)) // ldc
236: {
237: ldcIndex = code[i + 1] & 0xFF;
238: CpInfo ldcCpInfo = cf.getCpEntry(ldcIndex);
239: if (!(ldcCpInfo instanceof StringCpInfo)) {
240: ldcIndex = -1;
241: }
242: } else if ((opcode == 0x13) && (i + 2 < code.length)) // ldc_w
243: {
244: ldcIndex = ((code[i + 1] & 0xFF) << 8)
245: + (code[i + 2] & 0xFF);
246: CpInfo ldcCpInfo = cf.getCpEntry(ldcIndex);
247: if (!(ldcCpInfo instanceof StringCpInfo)) {
248: ldcIndex = -1;
249: }
250: }
251: if ((opcodePrev == 0x12 || opcodePrev == 0x13) // ldc or ldc_w
252: && ldcIndex != -1) // and is a StringCpInfo
253: {
254: boolean isClassForName = false;
255: if ((opcode == 0xB8) && (i + 2 < code.length)) // invokestatic
256: {
257: int invokeIndex = ((code[i + 1] & 0xFF) << 8)
258: + (code[i + 2] & 0xFF);
259: CpInfo cpInfo = cf.getCpEntry(invokeIndex);
260: if (cpInfo instanceof MethodrefCpInfo) {
261: MethodrefCpInfo entry = (MethodrefCpInfo) cpInfo;
262: ClassCpInfo classEntry = (ClassCpInfo) cf
263: .getCpEntry(entry.getClassIndex());
264: String className = ((Utf8CpInfo) cf
265: .getCpEntry(classEntry.getNameIndex()))
266: .getString();
267: NameAndTypeCpInfo ntEntry = (NameAndTypeCpInfo) cf
268: .getCpEntry(entry.getNameAndTypeIndex());
269: String name = ((Utf8CpInfo) cf
270: .getCpEntry(ntEntry.getNameIndex()))
271: .getString();
272: String descriptor = ((Utf8CpInfo) cf
273: .getCpEntry(ntEntry
274: .getDescriptorIndex()))
275: .getString();
276: if (("class$".equals(name) && ("(Ljava/lang/String;)Ljava/lang/Class;"
277: .equals(descriptor) || "(Ljava/lang/String;Z)Ljava/lang/Class;"
278: .equals(descriptor)))
279: || ("java/lang/Class".equals(className)
280: && "forName".equals(name) && "(Ljava/lang/String;)Ljava/lang/Class;"
281: .equals(descriptor))) {
282: isClassForName = true;
283: if (cpUpdate != null) {
284: // Update StringCpInfo index in ldc to new one
285: Object o = cpUpdate.get(new Integer(
286: ldcIndex));
287: if (o instanceof Integer) {
288: int remapStringIndex = ((Integer) o)
289: .intValue();
290: switch (opcodePrev) {
291: case 0x13: // ldc_w
292: code[i - 2] = 0;
293: // fallthru
294: case 0x12: // ldc
295: code[i - 1] = (byte) remapStringIndex;
296: break;
297: default: // error
298: throw new Exception(
299: ".class or Class.forName remap of non-ldc/ldc_w - please report this error");
300: }
301: }
302: }
303: }
304: }
305: }
306: if (cpToFlag != null) {
307: cpToFlag.updateFlag((StringCpInfo) cf
308: .getCpEntry(ldcIndex), ldcIndex,
309: isClassForName);
310: }
311: }
312: int bytes = getOpcodeBytes(opcode, i);
313: i += bytes;
314: opcodePrev = opcode;
315: }
316: return cpToFlag;
317: }
318:
319: /** Walk the code, adding pool references to Vector. */
320: protected void addCpRefs(Vector refs) throws Exception {
321: for (int i = 0; i < code.length; i++) {
322: int opcode = code[i] & 0xFF;
323: int index;
324: switch (opcode) {
325: // .class reference
326: case 0x12: // ldc
327: index = (code[i + 1] & 0xFF);
328: CpInfo cpInfo = cf.getCpEntry(index);
329: if (cpInfo instanceof ClassCpInfo) {
330: refs.addElement(cpInfo);
331: }
332: break;
333:
334: // .class reference
335: case 0x13: // ldc_w
336: index = ((code[i + 1] & 0xFF) << 8)
337: + (code[i + 2] & 0xFF);
338: cpInfo = cf.getCpEntry(index);
339: if (cpInfo instanceof ClassCpInfo) {
340: refs.addElement(cpInfo);
341: }
342: break;
343:
344: // class, array, interface type
345: case 0xBB: // new
346: case 0xBD: // anewarray
347: case 0xC0: // checkcast
348: case 0xC1: // instanceof
349: case 0xC5: // multianewarray
350: // static field
351: case 0xB2: // getstatic
352: case 0xB3: // putstatic
353: // non-static field
354: case 0xB4: // getfield
355: case 0xB5: // putfield
356: // static method
357: case 0xB8: // invokestatic
358: // non-static method
359: case 0xB6: // invokevirtual
360: case 0xB7: // invokespecial
361: case 0xB9: // invokeinterface
362: index = ((code[i + 1] & 0xFF) << 8)
363: + (code[i + 2] & 0xFF);
364: refs.addElement(cf.getCpEntry(index));
365: break;
366:
367: default:
368: // skip
369: break;
370: }
371: int bytes = getOpcodeBytes(opcode, i);
372: i += bytes;
373: }
374: }
375:
376: // Compute length of opcode arguments at offset
377: private int getOpcodeBytes(int opcode, int i) throws Exception {
378: int bytes = opcodeBytes(opcode);
379: if (bytes < 0) // variable length instructions
380: {
381: switch (opcode) {
382: case 0xAA: // tableswitch
383: bytes = 3 - (i % 4); // 0-3 byte pad
384: bytes += 4; // default value
385: int low = ((code[i + 1 + bytes] & 0xFF) << 24)
386: + ((code[i + 1 + bytes + 1] & 0xFF) << 16)
387: + ((code[i + 1 + bytes + 2] & 0xFF) << 8)
388: + (code[i + 1 + bytes + 3] & 0xFF);
389: bytes += 4; // low value
390: int high = ((code[i + 1 + bytes] & 0xFF) << 24)
391: + ((code[i + 1 + bytes + 1] & 0xFF) << 16)
392: + ((code[i + 1 + bytes + 2] & 0xFF) << 8)
393: + (code[i + 1 + bytes + 3] & 0xFF);
394: bytes += 4; // high value
395: if (high >= low) {
396: bytes += (high - low + 1) * 4; // jump offsets
397: }
398: break;
399: case 0xAB: // lookupswitch
400: bytes = 3 - (i % 4); // 0-3 byte pad
401: bytes += 4; // default value
402: int npairs = ((code[i + 1 + bytes] & 0xFF) << 24)
403: + ((code[i + 1 + bytes + 1] & 0xFF) << 16)
404: + ((code[i + 1 + bytes + 2] & 0xFF) << 8)
405: + (code[i + 1 + bytes + 3] & 0xFF);
406: bytes += 4; // npairs value
407: if (npairs >= 0) {
408: bytes += npairs * 8; // match / offset pairs
409: }
410: break;
411: case 0xC4: // wide
412: int wideOpcode = code[i + 1] & 0xFF;
413: switch (wideOpcode) {
414: case 0x15: // iload
415: case 0x16: // lload
416: case 0x17: // fload
417: case 0x18: // dload
418: case 0x19: // aload
419: case 0x36: // istore
420: case 0x37: // lstore
421: case 0x38: // fstore
422: case 0x39: // dstore
423: case 0x3A: // astore
424: case 0xA9: // ret
425: bytes = 3;
426: break;
427: case 0x84: // iinc
428: bytes = 5;
429: break;
430: default:
431: throw new Exception("Illegal wide opcode");
432: }
433: break;
434: default:
435: throw new Exception("Illegal variable length opcode");
436: }
437: }
438: return bytes;
439: }
440:
441: // Convert int to 2 char hex string
442: private static String toHexString(int i) {
443: String hex = "0" + Integer.toHexString(i);
444: return hex.substring(hex.length() - 2);
445: }
446: }
447:
448: /*
449: private static final String OPCODE_UNUSED = "<unused>";
450: private static final String OPCODE_RESERVED = "<reserved>";
451: private static final String[] opcodeName =
452: {
453: "nop", // 0x00
454: "aconst_null", // 0x01
455: "iconst_m1", // 0x02
456: "iconst_0", // 0x03
457: "iconst_1", // 0x04
458: "iconst_2", // 0x05
459: "iconst_3", // 0x06
460: "iconst_4", // 0x07
461: "iconst_5", // 0x08
462: "lconst_0", // 0x09
463: "lconst_1", // 0x0A
464: "fconst_0", // 0x0B
465: "fconst_1", // 0x0C
466: "fconst_2", // 0x0D
467: "dconst_0", // 0x0E
468: "dconst_1", // 0x0F
469: "bipush", // 0x10
470: "sipush", // 0x11
471: "ldc", // 0x12
472: "ldc_w", // 0x13
473: "ldc2_w", // 0x14
474: "iload", // 0x15
475: "lload", // 0x16
476: "fload", // 0x17
477: "dload", // 0x18
478: "aload", // 0x19
479: "iload_0", // 0x1A
480: "iload_1", // 0x1B
481: "iload_2", // 0x1C
482: "iload_3", // 0x1D
483: "lload_0", // 0x1E
484: "lload_1", // 0x1F
485: "lload_2", // 0x20
486: "lload_3", // 0x21
487: "fload_0", // 0x22
488: "fload_1", // 0x23
489: "fload_2", // 0x24
490: "fload_3", // 0x25
491: "dload_0", // 0x26
492: "dload_1", // 0x27
493: "dload_2", // 0x28
494: "dload_3", // 0x29
495: "aload_0", // 0x2A
496: "aload_1", // 0x2B
497: "aload_2", // 0x2C
498: "aload_3", // 0x2D
499: "iaload", // 0x2E
500: "laload", // 0x2F
501: "faload", // 0x30
502: "daload", // 0x31
503: "aaload", // 0x32
504: "baload", // 0x33
505: "caload", // 0x34
506: "saload", // 0x35
507: "istore", // 0x36
508: "lstore", // 0x37
509: "fstore", // 0x38
510: "dstore", // 0x39
511: "astore", // 0x3A
512: "istore_0", // 0x3B
513: "istore_1", // 0x3C
514: "istore_2", // 0x3D
515: "istore_3", // 0x3E
516: "lstore_0", // 0x3F
517: "lstore_1", // 0x40
518: "lstore_2", // 0x41
519: "lstore_3", // 0x42
520: "fstore_0", // 0x43
521: "fstore_1", // 0x44
522: "fstore_2", // 0x45
523: "fstore_3", // 0x46
524: "dstore_0", // 0x47
525: "dstore_1", // 0x48
526: "dstore_2", // 0x49
527: "dstore_3", // 0x4A
528: "astore_0", // 0x4B
529: "astore_1", // 0x4C
530: "astore_2", // 0x4D
531: "astore_3", // 0x4E
532: "iastore", // 0x4F
533: "lastore", // 0x50
534: "fastore", // 0x51
535: "dastore", // 0x52
536: "aastore", // 0x53
537: "bastore", // 0x54
538: "castore", // 0x55
539: "sastore", // 0x56
540: "pop", // 0x57
541: "pop2", // 0x58
542: "dup", // 0x59
543: "dup_x1", // 0x5A
544: "dup_x2", // 0x5B
545: "dup2", // 0x5C
546: "dup2_x1", // 0x5D
547: "dup2_x2", // 0x5E
548: "swap", // 0x5F
549: "iadd", // 0x60
550: "ladd", // 0x61
551: "fadd", // 0x62
552: "dadd", // 0x63
553: "isub", // 0x64
554: "lsub", // 0x65
555: "fsub", // 0x66
556: "dsub", // 0x67
557: "imul", // 0x68
558: "lmul", // 0x69
559: "fmul", // 0x6A
560: "dmul", // 0x6B
561: "idiv", // 0x6C
562: "ldiv", // 0x6D
563: "fdiv", // 0x6E
564: "ddiv", // 0x6F
565: "irem", // 0x70
566: "lrem", // 0x71
567: "frem", // 0x72
568: "drem", // 0x73
569: "ineg", // 0x74
570: "lneg", // 0x75
571: "fneg", // 0x76
572: "dneg", // 0x77
573: "ishl", // 0x78
574: "lshl", // 0x79
575: "ishr", // 0x7A
576: "lshr", // 0x7B
577: "iushr", // 0x7C
578: "lushr", // 0x7D
579: "iand", // 0x7E
580: "land", // 0x7F
581: "ior", // 0x80
582: "lor", // 0x81
583: "ixor", // 0x82
584: "lxor", // 0x83
585: "iinc", // 0x84
586: "i2l", // 0x85
587: "i2f", // 0x86
588: "i2d", // 0x87
589: "l2i", // 0x88
590: "l2f", // 0x89
591: "l2d", // 0x8A
592: "f2i", // 0x8B
593: "f2l", // 0x8C
594: "f2d", // 0x8D
595: "d2i", // 0x8E
596: "d2l", // 0x8F
597: "d2f", // 0x90
598: "i2b", // 0x91
599: "i2c", // 0x92
600: "i2s", // 0x93
601: "lcmp", // 0x94
602: "fcmpl", // 0x95
603: "fcmpg", // 0x96
604: "dcmpl", // 0x97
605: "dcmpg", // 0x98
606: "ifeq", // 0x99
607: "ifne", // 0x9A
608: "iflt", // 0x9B
609: "ifge", // 0x9C
610: "ifgt", // 0x9D
611: "ifle", // 0x9E
612: "if_icmpeq", // 0x9F
613: "if_icmpne", // 0xA0
614: "if_icmplt", // 0xA1
615: "if_icmpge", // 0xA2
616: "if_icmpgt", // 0xA3
617: "if_icmple", // 0xA4
618: "if_acmpeq", // 0xA5
619: "if_acmpne", // 0xA6
620: "goto", // 0xA7
621: "jsr", // 0xA8
622: "ret", // 0xA9
623: "tableswitch", // 0xAA
624: "lookupswitch", // 0xAB
625: "ireturn", // 0xAC
626: "lreturn", // 0xAD
627: "freturn", // 0xAE
628: "dreturn", // 0xAF
629: "areturn", // 0xB0
630: "return", // 0xB1
631: "getstatic", // 0xB2
632: "putstatic", // 0xB3
633: "getfield", // 0xB4
634: "putfield", // 0xB5
635: "invokevirtual", // 0xB6
636: "invokespecial", // 0xB7
637: "invokestatic", // 0xB8
638: "invokeinterface", // 0xB9
639: OPCODE_UNUSED, // 0xBA
640: "new", // 0xBB
641: "newarray", // 0xBC
642: "anewarray", // 0xBD
643: "arraylength", // 0xBE
644: "athrow", // 0xBF
645: "checkcast", // 0xC0
646: "instanceof", // 0xC1
647: "monitorenter", // 0xC2
648: "monitorexit", // 0xC3
649: "wide", // 0xC4
650: "multianewarray", // 0xC5
651: "ifnull", // 0xC6
652: "ifnonnull", // 0xC7
653: "goto_w", // 0xC8
654: "jsr_w", // 0xC9
655: OPCODE_RESERVED, // 0xCA
656: OPCODE_UNUSED, // 0xCB
657: OPCODE_UNUSED, // 0xCC
658: OPCODE_UNUSED, // 0xCD
659: OPCODE_UNUSED, // 0xCE
660: OPCODE_UNUSED, // 0xCF
661: OPCODE_UNUSED, // 0xD0
662: OPCODE_UNUSED, // 0xD1
663: OPCODE_UNUSED, // 0xD2
664: OPCODE_UNUSED, // 0xD3
665: OPCODE_UNUSED, // 0xD4
666: OPCODE_UNUSED, // 0xD5
667: OPCODE_UNUSED, // 0xD6
668: OPCODE_UNUSED, // 0xD7
669: OPCODE_UNUSED, // 0xD8
670: OPCODE_UNUSED, // 0xD9
671: OPCODE_UNUSED, // 0xDA
672: OPCODE_UNUSED, // 0xDB
673: OPCODE_UNUSED, // 0xDC
674: OPCODE_UNUSED, // 0xDD
675: OPCODE_UNUSED, // 0xDE
676: OPCODE_UNUSED, // 0xDF
677: OPCODE_UNUSED, // 0xE0
678: OPCODE_UNUSED, // 0xE1
679: OPCODE_UNUSED, // 0xE2
680: OPCODE_UNUSED, // 0xE3
681: OPCODE_UNUSED, // 0xE4
682: OPCODE_UNUSED, // 0xE5
683: OPCODE_UNUSED, // 0xE6
684: OPCODE_UNUSED, // 0xE7
685: OPCODE_UNUSED, // 0xE8
686: OPCODE_UNUSED, // 0xE9
687: OPCODE_UNUSED, // 0xEA
688: OPCODE_UNUSED, // 0xEB
689: OPCODE_UNUSED, // 0xEC
690: OPCODE_UNUSED, // 0xED
691: OPCODE_UNUSED, // 0xEE
692: OPCODE_UNUSED, // 0xEF
693: OPCODE_UNUSED, // 0xF0
694: OPCODE_UNUSED, // 0xF1
695: OPCODE_UNUSED, // 0xF2
696: OPCODE_UNUSED, // 0xF3
697: OPCODE_UNUSED, // 0xF4
698: OPCODE_UNUSED, // 0xF5
699: OPCODE_UNUSED, // 0xF6
700: OPCODE_UNUSED, // 0xF7
701: OPCODE_UNUSED, // 0xF8
702: OPCODE_UNUSED, // 0xF9
703: OPCODE_UNUSED, // 0xFA
704: OPCODE_UNUSED, // 0xFB
705: OPCODE_UNUSED, // 0xFC
706: OPCODE_UNUSED, // 0xFD
707: OPCODE_RESERVED, // 0xFE
708: OPCODE_RESERVED, // 0xFF
709: };
710: */
|