blob: 73c7e3ff3243b66fc14554b4382be6a9b55135e0 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package flash.swf.tools;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
/**
* This utility supports printing out AS3 ABC.
*/
public class AbcPrinter
{
private byte[] abc;
private int abcEnd;
private PrintWriter out;
private boolean showOffset;
private boolean showByteCode;
private int indent;
private int offset = 0;
private long numMetadata;
private int[] intConstants;
private long[] uintConstants;
private double[] floatConstants;
private String[] stringConstants;
private String[] namespaceConstants;
private String[][] namespaceSetConstants;
private MultiName[] multiNameConstants;
private String kAbcCorrupt = "Verify Error: ABC Corrupt";
private MethodInfo[] methods;
private String[] instanceNames;
private String[] Names;
private String indentString;
public AbcPrinter(byte[] abc, PrintWriter out, boolean showOffset, int indent, boolean showByteCode)
{
this.abc = abc;
this.abcEnd = abc.length;
this.out = out;
this.showOffset = showOffset;
this.showByteCode = showByteCode;
this.indent = indent;
char[] spaces = new char[indent * 2 + 1];
for (int i = 0; i < indent * 2; i++)
spaces[i] = ' ';
this.indentString = new String(spaces, 0, indent * 2);
}
public void print()
{
printOffset();
out.println(abc[offset++] + " " + abc[offset++] + " minor version");
printOffset();
out.println(abc[offset++] + " " + abc[offset++] + " major version");
printIntConstantPool();
printUintConstantPool();
printDoubleConstantPool();
printStringConstantPool();
printNamespaceConstantPool();
printNamespaceSetsConstantPool();
printMultiNameConstantPool();
printMethods();
printMetaData();
printClasses();
printScripts();
printBodies();
}
final int TRAIT_Slot = 0x00;
final int TRAIT_Method = 0x01;
final int TRAIT_Getter = 0x02;
final int TRAIT_Setter = 0x03;
final int TRAIT_Class = 0x04;
final int TRAIT_Function = 0x05;
final int TRAIT_Const = 0x06;
final String[] traitKinds = {
"var",
"function",
"function get",
"function set",
"class",
"function",
"const"
};
char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
final int OP_bkpt = 0x01;
final int OP_nop = 0x02;
final int OP_throw = 0x03;
final int OP_getsuper = 0x04;
final int OP_setsuper = 0x05;
final int OP_dxns = 0x06;
final int OP_dxnslate = 0x07;
final int OP_kill = 0x08;
final int OP_label = 0x09;
final int OP_ifnlt = 0x0C;
final int OP_ifnle = 0x0D;
final int OP_ifngt = 0x0E;
final int OP_ifnge = 0x0F;
final int OP_jump = 0x10;
final int OP_iftrue = 0x11;
final int OP_iffalse = 0x12;
final int OP_ifeq = 0x13;
final int OP_ifne = 0x14;
final int OP_iflt = 0x15;
final int OP_ifle = 0x16;
final int OP_ifgt = 0x17;
final int OP_ifge = 0x18;
final int OP_ifstricteq = 0x19;
final int OP_ifstrictne = 0x1A;
final int OP_lookupswitch = 0x1B;
final int OP_pushwith = 0x1C;
final int OP_popscope = 0x1D;
final int OP_nextname = 0x1E;
final int OP_hasnext = 0x1F;
final int OP_pushnull = 0x20;
final int OP_pushundefined = 0x21;
final int OP_pushintant = 0x22;
final int OP_nextvalue = 0x23;
final int OP_pushbyte = 0x24;
final int OP_pushshort = 0x25;
final int OP_pushtrue = 0x26;
final int OP_pushfalse = 0x27;
final int OP_pushnan = 0x28;
final int OP_pop = 0x29;
final int OP_dup = 0x2A;
final int OP_swap = 0x2B;
final int OP_pushstring = 0x2C;
final int OP_pushint = 0x2D;
final int OP_pushuint = 0x2E;
final int OP_pushdouble = 0x2F;
final int OP_pushscope = 0x30;
final int OP_pushnamespace = 0x31;
final int OP_hasnext2 = 0x32;
final int OP_newfunction = 0x40;
final int OP_call = 0x41;
final int OP_construct = 0x42;
final int OP_callmethod = 0x43;
final int OP_callstatic = 0x44;
final int OP_callsuper = 0x45;
final int OP_callproperty = 0x46;
final int OP_returnvoid = 0x47;
final int OP_returnvalue = 0x48;
final int OP_constructsuper = 0x49;
final int OP_constructprop = 0x4A;
final int OP_callsuperid = 0x4B;
final int OP_callproplex = 0x4C;
final int OP_callinterface = 0x4D;
final int OP_callsupervoid = 0x4E;
final int OP_callpropvoid = 0x4F;
final int OP_newobject = 0x55;
final int OP_newarray = 0x56;
final int OP_newactivation = 0x57;
final int OP_newclass = 0x58;
final int OP_getdescendants = 0x59;
final int OP_newcatch = 0x5A;
final int OP_findpropstrict = 0x5D;
final int OP_findproperty = 0x5E;
final int OP_finddef = 0x5F;
final int OP_getlex = 0x60;
final int OP_setproperty = 0x61;
final int OP_getlocal = 0x62;
final int OP_setlocal = 0x63;
final int OP_getglobalscope = 0x64;
final int OP_getscopeobject = 0x65;
final int OP_getproperty = 0x66;
final int OP_getpropertylate = 0x67;
final int OP_initproperty = 0x68;
final int OP_setpropertylate = 0x69;
final int OP_deleteproperty = 0x6A;
final int OP_deletepropertylate = 0x6B;
final int OP_getslot = 0x6C;
final int OP_setslot = 0x6D;
final int OP_getglobalslot = 0x6E;
final int OP_setglobalslot = 0x6F;
final int OP_convert_s = 0x70;
final int OP_esc_xelem = 0x71;
final int OP_esc_xattr = 0x72;
final int OP_convert_i = 0x73;
final int OP_convert_u = 0x74;
final int OP_convert_d = 0x75;
final int OP_convert_b = 0x76;
final int OP_convert_o = 0x77;
final int OP_coerce = 0x80;
final int OP_coerce_b = 0x81;
final int OP_coerce_a = 0x82;
final int OP_coerce_i = 0x83;
final int OP_coerce_d = 0x84;
final int OP_coerce_s = 0x85;
final int OP_astype = 0x86;
final int OP_astypelate = 0x87;
final int OP_coerce_u = 0x88;
final int OP_coerce_o = 0x89;
final int OP_negate = 0x90;
final int OP_increment = 0x91;
final int OP_inclocal = 0x92;
final int OP_decrement = 0x93;
final int OP_declocal = 0x94;
final int OP_typeof = 0x95;
final int OP_not = 0x96;
final int OP_bitnot = 0x97;
final int OP_concat = 0x9A;
final int OP_add_d = 0x9B;
final int OP_add = 0xA0;
final int OP_subtract = 0xA1;
final int OP_multiply = 0xA2;
final int OP_divide = 0xA3;
final int OP_modulo = 0xA4;
final int OP_lshift = 0xA5;
final int OP_rshift = 0xA6;
final int OP_urshift = 0xA7;
final int OP_bitand = 0xA8;
final int OP_bitor = 0xA9;
final int OP_bitxor = 0xAA;
final int OP_equals = 0xAB;
final int OP_strictequals = 0xAC;
final int OP_lessthan = 0xAD;
final int OP_lessequals = 0xAE;
final int OP_greaterthan = 0xAF;
final int OP_greaterequals = 0xB0;
final int OP_instanceof = 0xB1;
final int OP_istype = 0xB2;
final int OP_istypelate = 0xB3;
final int OP_in = 0xB4;
final int OP_increment_i = 0xC0;
final int OP_decrement_i = 0xC1;
final int OP_inclocal_i = 0xC2;
final int OP_declocal_i = 0xC3;
final int OP_negate_i = 0xC4;
final int OP_add_i = 0xC5;
final int OP_subtract_i = 0xC6;
final int OP_multiply_i = 0xC7;
final int OP_getlocal0 = 0xD0;
final int OP_getlocal1 = 0xD1;
final int OP_getlocal2 = 0xD2;
final int OP_getlocal3 = 0xD3;
final int OP_setlocal0 = 0xD4;
final int OP_setlocal1 = 0xD5;
final int OP_setlocal2 = 0xD6;
final int OP_setlocal3 = 0xD7;
final int OP_debug = 0xEF;
final int OP_debugline = 0xF0;
final int OP_debugfile = 0xF1;
final int OP_bkptline = 0xF2;
String[] opNames = {
"OP_0x00 ",
"bkpt ",
"nop ",
"throw ",
"getsuper ",
"setsuper ",
"dxns ",
"dxnslate ",
"kill ",
"label ",
"OP_0x0A ",
"OP_0x0B ",
"ifnlt ",
"ifnle ",
"ifngt ",
"ifnge ",
"jump ",
"iftrue ",
"iffalse ",
"ifeq ",
"ifne ",
"iflt ",
"ifle ",
"ifgt ",
"ifge ",
"ifstricteq ",
"ifstrictne ",
"lookupswitch ",
"pushwith ",
"popscope ",
"nextname ",
"hasnext ",
"pushnull ",
"pushundefined ",
"pushconstant ",
"nextvalue ",
"pushbyte ",
"pushshort ",
"pushtrue ",
"pushfalse ",
"pushnan ",
"pop ",
"dup ",
"swap ",
"pushstring ",
"pushint ",
"pushuint ",
"pushdouble ",
"pushscope ",
"pushnamespace ",
"hasnext2 ",
"OP_0x33 ",
"OP_0x34 ",
"OP_0x35 ",
"OP_0x36 ",
"OP_0x37 ",
"OP_0x38 ",
"OP_0x39 ",
"OP_0x3A ",
"OP_0x3B ",
"OP_0x3C ",
"OP_0x3D ",
"OP_0x3E ",
"OP_0x3F ",
"newfunction ",
"call ",
"construct ",
"callmethod ",
"callstatic ",
"callsuper ",
"callproperty ",
"returnvoid ",
"returnvalue ",
"constructsuper",
"constructprop ",
"callsuperid ",
"callproplex ",
"callinterface ",
"callsupervoid ",
"callpropvoid ",
"OP_0x50 ",
"OP_0x51 ",
"OP_0x52 ",
"OP_0x53 ",
"OP_0x54 ",
"newobject ",
"newarray ",
"newactivation ",
"newclass ",
"getdescendants",
"newcatch ",
"OP_0x5B ",
"OP_0x5C ",
"findpropstrict",
"findproperty ",
"finddef ",
"getlex ",
"setproperty ",
"getlocal ",
"setlocal ",
"getglobalscope",
"getscopeobject",
"getproperty ",
"OP_0x67 ",
"initproperty ",
"OP_0x69 ",
"deleteproperty",
"OP_0x6A ",
"getslot ",
"setslot ",
"getglobalslot ",
"setglobalslot ",
"convert_s ",
"esc_xelem ",
"esc_xattr ",
"convert_i ",
"convert_u ",
"convert_d ",
"convert_b ",
"convert_o ",
"checkfilter ",
"OP_0x79 ",
"OP_0x7A ",
"OP_0x7B ",
"OP_0x7C ",
"OP_0x7D ",
"OP_0x7E ",
"OP_0x7F ",
"coerce ",
"coerce_b ",
"coerce_a ",
"coerce_i ",
"coerce_d ",
"coerce_s ",
"astype ",
"astypelate ",
"coerce_u ",
"coerce_o ",
"OP_0x8A ",
"OP_0x8B ",
"OP_0x8C ",
"OP_0x8D ",
"OP_0x8E ",
"OP_0x8F ",
"negate ",
"increment ",
"inclocal ",
"decrement ",
"declocal ",
"typeof ",
"not ",
"bitnot ",
"OP_0x98 ",
"OP_0x99 ",
"concat ",
"add_d ",
"OP_0x9C ",
"OP_0x9D ",
"OP_0x9E ",
"OP_0x9F ",
"add ",
"subtract ",
"multiply ",
"divide ",
"modulo ",
"lshift ",
"rshift ",
"urshift ",
"bitand ",
"bitor ",
"bitxor ",
"equals ",
"strictequals ",
"lessthan ",
"lessequals ",
"greaterthan ",
"greaterequals ",
"instanceof ",
"istype ",
"istypelate ",
"in ",
"OP_0xB5 ",
"OP_0xB6 ",
"OP_0xB7 ",
"OP_0xB8 ",
"OP_0xB9 ",
"OP_0xBA ",
"OP_0xBB ",
"OP_0xBC ",
"OP_0xBD ",
"OP_0xBE ",
"OP_0xBF ",
"increment_i ",
"decrement_i ",
"inclocal_i ",
"declocal_i ",
"negate_i ",
"add_i ",
"subtract_i ",
"multiply_i ",
"OP_0xC8 ",
"OP_0xC9 ",
"OP_0xCA ",
"OP_0xCB ",
"OP_0xCC ",
"OP_0xCD ",
"OP_0xCE ",
"OP_0xCF ",
"getlocal0 ",
"getlocal1 ",
"getlocal2 ",
"getlocal3 ",
"setlocal0 ",
"setlocal1 ",
"setlocal2 ",
"setlocal3 ",
"OP_0xD8 ",
"OP_0xD9 ",
"OP_0xDA ",
"OP_0xDB ",
"OP_0xDC ",
"OP_0xDD ",
"OP_0xDE ",
"OP_0xDF ",
"OP_0xE0 ",
"OP_0xE1 ",
"OP_0xE2 ",
"OP_0xE3 ",
"OP_0xE4 ",
"OP_0xE5 ",
"OP_0xE6 ",
"OP_0xE7 ",
"OP_0xE8 ",
"OP_0xE9 ",
"OP_0xEA ",
"OP_0xEB ",
"OP_0xEC ",
"OP_0xED ",
"OP_0xEE ",
"debug ",
"debugline ",
"debugfile ",
"bkptline ",
"timestamp ",
"OP_0xF4 ",
"verifypass ",
"alloc ",
"mark ",
"wb ",
"prologue ",
"sendenter ",
"doubletoatom ",
"sweep ",
"codegenop ",
"verifyop ",
"decode "
};
String hex(byte b)
{
return new StringBuilder().append(hexChars[(b >> 4) & 0xF]).append(hexChars[b & 0xF]).toString();
}
void printOffset()
{
if (showOffset)
out.print(indentString + "offset " + offset + ": ");
else
out.print(indentString);
}
int readS24()
{
int b = abc[offset++];
b &= 0xFF;
b |= abc[offset++] << 8;
b &= 0xFFFF;
b |= abc[offset++] << 16;
return b;
}
long readU32()
{
long b = abc[offset++];
b &= 0xFF;
long u32 = b;
if (!((u32 & 0x00000080) == 0x00000080))
return u32;
b = abc[offset++];
b &= 0xFF;
u32 = u32 & 0x0000007f | b << 7;
if (!((u32 & 0x00004000) == 0x00004000))
return u32;
b = abc[offset++];
b &= 0xFF;
u32 = u32 & 0x00003fff | b << 14;
if (!((u32 & 0x00200000) == 0x00200000))
return u32;
b = abc[offset++];
b &= 0xFF;
u32 = u32 & 0x001fffff | b << 21;
if (!((u32 & 0x10000000) == 0x10000000))
return u32;
b = abc[offset++];
b &= 0xFF;
u32 = u32 & 0x0fffffff | b << 28;
return u32;
}
String readUTFBytes(long n)
{
StringWriter sw = new StringWriter();
for (int i = 0; i < n; i++)
{
sw.write(abc[offset++]);
}
return sw.toString();
}
void printIntConstantPool()
{
long n = readU32();
printOffset();
out.println(n + " Integer Constant Pool Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
intConstants = new int[(n > 0) ? (int)n : 1];
intConstants[0] = 0;
for (int i = 1; i < n; i++)
{
long val = readU32();
intConstants[i] = (int)val;
printOffset();
out.println(val);
}
}
void printUintConstantPool()
{
long n = readU32();
printOffset();
out.println(n + " Unsigned Integer Constant Pool Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
uintConstants = new long[(n > 0) ? (int)n : 1];
uintConstants[0] = 0;
for (int i = 1; i < n; i++)
{
long val = readU32();
uintConstants[i] = (int)val;
printOffset();
out.println(val);
}
}
void printDoubleConstantPool()
{
long n = readU32();
printOffset();
out.println(n + " Floating Point Constant Pool Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
if (n > 0)
offset += (n - 1) * 8;
}
void printStringConstantPool()
{
long n = readU32();
printOffset();
out.println(n + " String Constant Pool Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
stringConstants = new String[(n > 0) ? (int)n : 1];
stringConstants[0] = "";
for (int i = 1; i < n; i++)
{
printOffset();
long strlen = readU32();
if (((strlen & 0xc0000000) != 0) || abcEnd <= offset + strlen)
out.println(kAbcCorrupt + "strlen");
String s = readUTFBytes(strlen);
stringConstants[i] = s;
s = s.replace("\r\n", "\\r\\n");
s = s.replace("\n", "\\n");
s = s.replace("\r", "\\r");
out.println(" " + s);
}
}
void printNamespaceConstantPool()
{
long n = readU32();
printOffset();
out.println(n + " Namespace Constant Pool Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
namespaceConstants = new String[(n > 0) ? (int)n : 1];
namespaceConstants[0] = "public";
for (int i = 1; i < n; i++)
{
printOffset();
byte b = abc[offset++];
String s;
if (b == 5)
{
readU32();
s = "private";
}
else
{
s = stringConstants[(int)readU32()];
}
namespaceConstants[i] = s;
out.println(" " + s);
}
}
void printNamespaceSetsConstantPool()
{
long n = readU32();
printOffset();
out.println(n + " Namespace Set Constant Pool Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
namespaceSetConstants = new String[(n > 0) ? (int)n : 1][];
namespaceSetConstants[0] = new String[0];
for (int i = 1; i < n; i++)
{
long val = readU32();
if (val > abcEnd - offset)
out.println(kAbcCorrupt);
String[] nsset = new String[(int)val];
namespaceSetConstants[i] = nsset;
for (int j = 0; j < val; j++)
{
nsset[j] = namespaceConstants[(int)readU32()];
}
}
}
void printMultiNameConstantPool()
{
long n = readU32();
printOffset();
out.println(n + " MultiName Constant Pool Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
multiNameConstants = new MultiName[(n > 0) ? (int)n : 1];
multiNameConstants[0] = new MultiName();
for (int i = 1; i < n; i++)
{
printOffset();
byte b = abc[offset++];
multiNameConstants[i] = new MultiName();
multiNameConstants[i].kind = b;
switch (b)
{
case 0x07: // QName
case 0x0D:
multiNameConstants[i].long1 = (int)readU32();
multiNameConstants[i].long2 = (int)readU32();
break;
case 0x0F: // RTQName
case 0x10:
multiNameConstants[i].long1 = (int)readU32();
break;
case 0x11: // RTQNameL
case 0x12:
break;
case 0x13: // NameL
case 0x14:
break;
case 0x09:
case 0x0E:
multiNameConstants[i].long1 = (int)readU32();
multiNameConstants[i].long2 = (int)readU32();
break;
case 0x1B:
case 0x1C:
multiNameConstants[i].long1 = (int)readU32();
break;
case 0x1D:
int nameIndex = (int)readU32();
MultiName mn = multiNameConstants[nameIndex];
int count = (int)readU32();
if (count != 1)
out.println(kAbcCorrupt + "more than one typename");
MultiName types[] = new MultiName[count];
for (int t = 0; t < count; t++)
{
int typeIndex = (int)readU32();
types[t] = multiNameConstants[typeIndex];
}
multiNameConstants[i].typeName = mn;
multiNameConstants[i].types = types;
}
out.println(multiNameConstants[i]);
}
// verify vectors (yes, the AVM does this)
for (int i = 1; i < n; i++)
{
MultiName mn = multiNameConstants[i];
if (mn.kind != 0x1D)
continue;
MultiName typeName = mn.typeName;
if (typeName == null) // this came up as null in a working SWF.
continue;
if (typeName.kind == 0x1D)
out.println(kAbcCorrupt + "typename is also a typename");
HashMap<MultiName, String> seenMap = new HashMap<MultiName, String>();
MultiName type = mn.types[0];
while (type != null)
{
if (type.kind != 0x1D)
break;
seenMap.put(type, type.toString());
type = type.types[0];
if (seenMap.containsKey(type))
out.println(kAbcCorrupt + "type cycle");
}
}
}
void printMethods()
{
long n = readU32();
printOffset();
out.println(n + " Method Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
methods = new MethodInfo[(int)n];
for (int i = 0; i < n; i++)
{
int start = offset;
printOffset();
MethodInfo m = methods[i] = new MethodInfo();
m.paramCount = (int)readU32();
m.returnType = (int)readU32();
m.params = new int[m.paramCount];
for (int j = 0; j < m.paramCount; j++)
{
m.params[j] = (int)readU32();
}
int nameIndex = (int)readU32();
if (nameIndex > 0)
m.name = stringConstants[nameIndex];
else
m.name = "no name";
m.flags = abc[offset++];
if ((m.flags & 0x8) == 0x8)
{
// read in optional parameter info
m.optionCount = (int)readU32();
m.optionIndex = new int[m.optionCount];
m.optionKinds = new int[m.optionCount];
for (int k = 0; k < m.optionCount; k++)
{
m.optionIndex[k] = (int)readU32();
m.optionKinds[k] = abc[offset++];
}
if (m.optionCount == 0 || m.optionCount > m.paramCount)
out.println(kAbcCorrupt);
}
if ((m.flags & 0x80) == 0x80)
{
// read in parameter names info
m.paramNames = new int[m.paramCount];
for (int k = 0; k < m.paramCount; k++)
{
m.paramNames[k] = (int)readU32();
}
}
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.print(m.name + "(");
for (int x = 0; x < m.paramCount; x++)
{
out.print(multiNameConstants[m.params[x]]);
if (x < m.paramCount - 1)
out.print(",");
}
out.print("):");
out.println(multiNameConstants[m.returnType] + " ");
}
}
void printMetaData()
{
long n = readU32();
printOffset();
out.println(n + " Metadata Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
numMetadata = n;
for (int i = 0; i < n; i++)
{
int start = offset;
printOffset();
String s = stringConstants[(int)readU32()];
long val = readU32();
for (int j = 0; j < val; j++)
{
s += " " + stringConstants[(int)readU32()];
}
for (int j = 0; j < val; j++)
{
s += " " + stringConstants[(int)readU32()];
}
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.println(s);
}
}
void printClasses()
{
long n = readU32();
printOffset();
out.println(n + " Instance Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
instanceNames = new String[(int)n];
for (int i = 0; i < n; i++)
{
int start = offset;
printOffset();
String name = multiNameConstants[(int)readU32()].toString();
instanceNames[i] = name;
String base = multiNameConstants[(int)readU32()].toString();
int b = abc[offset++];
if ((b & 0x8) == 0x8)
readU32(); // eat protected namespace
long val = readU32();
if (val >= 0x10000000)
out.println(kAbcCorrupt);
String s = "";
for (int j = 0; j < val; j++)
{
s += " " + multiNameConstants[(int)readU32()].toString();
}
int init = (int)readU32(); // eat init method
MethodInfo mi = methods[init];
mi.name = name;
mi.className = name;
mi.kind = TRAIT_Method;
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.print("Instance Traits for: " + name + " ");
if (base.length() > 0)
out.print("extends " + base + " ");
if (s.length() > 0)
out.print("implements " + s);
out.println("");
int numTraits = (int)readU32(); // number of traits
printOffset();
out.println(numTraits + " Traits Entries");
if (numTraits > abcEnd - offset)
out.println(kAbcCorrupt);
for (int j = 0; j < numTraits; j++)
{
printOffset();
start = offset;
s = multiNameConstants[(int)readU32()].toString(); // eat trait name;
b = abc[offset++];
int kind = b & 0xf;
switch (kind)
{
case 0x00: // slot
case 0x06: // const
readU32(); // id
readU32(); // type
int index = (int)readU32(); // index;
if (index != 0)
offset++; // kind
break;
case 0x04: // class
readU32(); // id
readU32(); // value;
break;
case 0x01:
case 0x02:
case 0x03:
case 0x05:
readU32(); // id
mi = methods[(int)readU32()]; // method
mi.name = s;
mi.className = name;
mi.kind = kind;
if (mi.sawTraits)
out.println(kAbcCorrupt + "sawTraits");
mi.sawTraits = true;
break;
default:
out.println(kAbcCorrupt + "Unknown Trait");
}
if ((b >> 4 & 0x4) == 0x4)
{
val = readU32(); // metadata count
for (int k = 0; k < val; k++)
{
long index = readU32(); // metadata
if (index >= numMetadata)
out.println(kAbcCorrupt);
}
}
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.println(s);
}
}
printOffset();
out.println(n + " Class Entries");
for (int i = 0; i < n; i++)
{
int start = offset;
printOffset();
MethodInfo mi = methods[(int)readU32()];
String name = instanceNames[i];
mi.name = name + "$cinit";
mi.className = name;
mi.kind = TRAIT_Method;
String base = "Class";
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.print("Class Traits for: " + name + " ");
if (base.length() > 0)
out.print("extends " + base + " ");
out.println("");
int numTraits = (int)readU32(); // number of traits
printOffset();
out.println(numTraits + " Traits Entries");
if (numTraits > abcEnd - offset)
out.println(kAbcCorrupt);
for (int j = 0; j < numTraits; j++)
{
printOffset();
start = offset;
String s = multiNameConstants[(int)readU32()].toString(); // eat trait name;
int b = abc[offset++];
int kind = b & 0xf;
switch (kind)
{
case 0x00: // slot
case 0x06: // const
readU32(); // id
readU32(); // type
int index = (int)readU32(); // index;
if (index != 0)
offset++; // kind
break;
case 0x04: // class
readU32(); // id
readU32(); // value;
break;
case 0x01:
case 0x02:
case 0x03:
case 0x05:
readU32(); // id
mi = methods[(int)readU32()]; // method
mi.name = s;
mi.className = name;
mi.kind = kind;
if (mi.sawTraits)
out.println(kAbcCorrupt + "sawTraits");
mi.sawTraits = true;
break;
default:
out.println(kAbcCorrupt);
}
if ((b >> 4 & 0x4) == 0x4)
{
int val = (int)readU32(); // metadata count
for (int k = 0; k < val; k++)
{
long index = readU32(); // metadata
if (index > numMetadata)
out.println(kAbcCorrupt);
}
}
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.println(s);
}
}
}
void printScripts()
{
long n = readU32();
printOffset();
out.println(n + " Script Entries");
if (n > abcEnd - offset)
out.println(kAbcCorrupt);
for (int i = 0; i < n; i++)
{
int start = offset;
printOffset();
String name = "script" + Integer.toString(i);
int init = (int)readU32(); // eat init method
MethodInfo mi = methods[init];
mi.name = name + "$init";
mi.className = name;
mi.kind = TRAIT_Method;
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.println(name + " ");
int numTraits = (int)readU32(); // number of traits
printOffset();
out.println(numTraits + " Traits Entries");
if (numTraits > abcEnd - offset)
out.println(kAbcCorrupt);
for (int j = 0; j < numTraits; j++)
{
printOffset();
start = offset;
String s = multiNameConstants[(int)readU32()].toString(); // eat trait name;
int b = abc[offset++];
int kind = b & 0xf;
switch (kind)
{
case 0x00: // slot
case 0x06: // const
if (kind == 0x00)
s = "slot trait: " + s;
else
s = "const trait: " + s;
readU32(); // id
readU32(); // type
int index = (int)readU32(); // index;
if (index != 0)
offset++; // kind
break;
case 0x04: // class
s = "class trait: " + s;
readU32(); // id
s += " " + instanceNames[(int)readU32()]; // value;
break;
case 0x01:
case 0x02:
case 0x03:
case 0x05:
readU32(); // id
mi = methods[(int)readU32()]; // method
mi.name = s;
mi.className = name;
mi.kind = kind;
if (mi.sawTraits)
out.println(kAbcCorrupt + "sawTraits");
mi.sawTraits = true;
break;
default:
out.println(kAbcCorrupt + "Unknown trait");
}
if ((b >> 4 & 0x4) == 0x4)
{
int val = (int)readU32(); // metadata count
for (int k = 0; k < val; k++)
{
long index = readU32(); // metadata
if (index > numMetadata)
out.println(kAbcCorrupt);
}
}
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.println(s);
}
}
}
void printBodies()
{
long n = readU32();
printOffset();
out.println(n + " Method Bodies");
for (int i = 0; i < n; i++)
{
printOffset();
int start = offset;
int methodIndex = (int)readU32();
int maxStack = (int)readU32();
int localCount = (int)readU32();
int initScopeDepth = (int)readU32();
int maxScopeDepth = (int)readU32();
int codeLength = (int)readU32();
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
for (int x = offset - start; x < 7; x++)
{
out.print(" ");
}
}
if (abcEnd < codeLength + offset)
out.println(kAbcCorrupt);
MethodInfo mi = methods[methodIndex];
out.print(traitKinds[mi.kind] + " ");
out.print(mi.className + "::" + mi.name + "(");
for (int x = 0; x < mi.paramCount - 1; x++)
{
out.print(multiNameConstants[mi.params[x]].toString() + ", ");
}
if (mi.paramCount > 0)
out.print(multiNameConstants[mi.params[mi.paramCount - 1]].toString());
out.print("):");
out.println(multiNameConstants[mi.returnType].toString());
printOffset();
out.print("maxStack:" + maxStack + " localCount:" + localCount + " ");
out.println("initScopeDepth:" + initScopeDepth + " maxScopeDepth:" + maxScopeDepth);
LabelMgr labels = new LabelMgr();
int stopAt = codeLength + offset;
while (offset < stopAt)
{
String s = "";
start = offset;
printOffset();
int opcode = abc[offset++] & 0xFF;
if (opcode == OP_label || labels.hasLabelAt(offset - 1))
{
s = labels.getLabelAt(offset - 1) + ":";
while (s.length() < 4)
s += " ";
}
else
s = " ";
s += opNames[opcode];
s += opNames[opcode].length() < 8 ? "\t\t" : "\t";
switch (opcode)
{
case OP_debugfile:
case OP_pushstring:
s += '"' + stringConstants[(int)readU32()].replaceAll("\n","\\n").replaceAll("\t","\\t") + '"';
break;
case OP_pushnamespace:
s += namespaceConstants[(int)readU32()];
break;
case OP_pushint:
int k = intConstants[(int)readU32()];
s += k + "\t// 0x" + Integer.toHexString(k);
break;
case OP_pushuint:
long u = uintConstants[(int)readU32()];
s += u + "\t// 0x" + Long.toHexString(u);
break;
case OP_pushdouble:
int f = (int)readU32();
s += "floatConstant" + f;
break;
case OP_getsuper:
case OP_setsuper:
case OP_getproperty:
case OP_initproperty:
case OP_setproperty:
case OP_getlex:
case OP_findpropstrict:
case OP_findproperty:
case OP_finddef:
case OP_deleteproperty:
case OP_istype:
case OP_coerce:
case OP_astype:
case OP_getdescendants:
s += multiNameConstants[(int)readU32()];
break;
case OP_constructprop:
case OP_callproperty:
case OP_callproplex:
case OP_callsuper:
case OP_callsupervoid:
case OP_callpropvoid:
s += multiNameConstants[(int)readU32()];
s += " (" + readU32() + ")";
break;
case OP_newfunction:
int method_id = (int)readU32();
s += methods[method_id].name;
// abc.methods[method_id].anon = true (do later?)
break;
case OP_callstatic:
s += methods[(int)readU32()].name;
s += " (" + readU32() + ")";
break;
case OP_newclass:
s += instanceNames[(int)readU32()];
break;
case OP_lookupswitch:
int pos = offset - 1;
int target = pos + readS24();
int maxindex = (int)readU32();
s += "default:" + labels.getLabelAt(target); // target + "("+(target-pos)+")"
s += " maxcase:" + Integer.toString(maxindex);
for (int m = 0; m <= maxindex; m++)
{
target = pos + readS24();
s += " " + labels.getLabelAt(target); // target + "("+(target-pos)+")"
}
break;
case OP_jump:
case OP_iftrue: case OP_iffalse:
case OP_ifeq: case OP_ifne:
case OP_ifge: case OP_ifnge:
case OP_ifgt: case OP_ifngt:
case OP_ifle: case OP_ifnle:
case OP_iflt: case OP_ifnlt:
case OP_ifstricteq: case OP_ifstrictne:
int delta = readS24();
int targ = offset + delta;
//s += target + " ("+offset+")"
s += labels.getLabelAt(targ);
if (!(labels.hasLabelAt(offset)))
s += "\n";
break;
case OP_inclocal:
case OP_declocal:
case OP_inclocal_i:
case OP_declocal_i:
case OP_getlocal:
case OP_kill:
case OP_setlocal:
case OP_debugline:
case OP_getglobalslot:
case OP_getslot:
case OP_setglobalslot:
case OP_setslot:
case OP_pushshort:
case OP_newcatch:
s += readU32();
break;
case OP_debug:
s += Integer.toString(abc[offset++] & 0xFF);
s += " " + readU32();
s += " " + Integer.toString(abc[offset++] & 0xFF);
s += " " + readU32();
break;
case OP_newobject:
s += "{" + readU32() + "}";
break;
case OP_newarray:
s += "[" + readU32() + "]";
break;
case OP_call:
case OP_construct:
case OP_constructsuper:
s += "(" + readU32() + ")";
break;
case OP_pushbyte:
case OP_getscopeobject:
s += abc[offset++];
break;
case OP_hasnext2:
s += readU32() + " " + readU32();
default:
/*if (opNames[opcode] == ("0x"+opcode.toString(16).toUpperCase()))
s += " UNKNOWN OPCODE"*/
break;
}
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
for (int x = offset - start; x < 7; x++)
{
out.print(" ");
}
}
out.println(s);
}
int exCount = (int)readU32();
printOffset();
out.println(exCount + " Extras");
for (int j = 0; j < exCount; j++)
{
start = offset;
printOffset();
int from = (int)readU32();
int to = (int)readU32();
int target = (int)readU32();
int typeIndex = (int)readU32();
int nameIndex = (int)readU32();
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.print(multiNameConstants[nameIndex] + " ");
out.print("type:" + multiNameConstants[typeIndex] + " from:" + from + " ");
out.println("to:" + to + " target:" + target);
}
int numTraits = (int)readU32(); // number of traits
printOffset();
out.println(numTraits + " Traits Entries");
if (numTraits > abcEnd - offset)
out.println(kAbcCorrupt);
for (int j = 0; j < numTraits; j++)
{
printOffset();
start = offset;
String s = multiNameConstants[(int)readU32()].toString(); // eat trait name;
int b = abc[offset++];
int kind = b & 0xf;
switch (kind)
{
case 0x00: // slot
case 0x06: // const
readU32(); // id
readU32(); // type
int index = (int)readU32(); // index;
if (index != 0)
offset++; // kind
break;
case 0x04: // class
readU32(); // id
readU32(); // value;
break;
case 0x01:
case 0x02:
case 0x03:
case 0x05:
readU32(); // id
readU32(); // method
break;
default:
out.println(kAbcCorrupt);
}
if ((b >> 4 & 0x4) == 0x4)
{
int val = (int)readU32(); // metadata count
for (int k = 0; k < val; k++)
{
long index = readU32(); // metadata
if (index > numMetadata)
out.println(kAbcCorrupt);
}
}
if (showByteCode)
{
for (int x = start; x < offset; x++)
{
out.print(hex(abc[(int)x]) + " ");
}
}
out.println(s);
}
out.println("");
}
}
class MultiName
{
public MultiName()
{
}
public int kind;
public int long1;
public int long2;
public MultiName typeName;
public MultiName types[];
public String toString()
{
String s = "";
String[] nsSet;
int len;
int j;
switch (kind)
{
case 0x07: // QName
case 0x0D:
s = namespaceConstants[long1] + ":";
s += stringConstants[long2];
break;
case 0x0F: // RTQName
case 0x10:
s = stringConstants[long1];
break;
case 0x11: // RTQNameL
case 0x12:
s = "RTQNameL";
break;
case 0x13: // NameL
case 0x14:
s = "NameL";
break;
case 0x09:
case 0x0E:
nsSet = namespaceSetConstants[long2];
len = nsSet.length;
for (j = 0; j < len - 1; j++)
{
s += nsSet[j] + ",";
}
if (len > 0)
s += nsSet[len - 1] + ":";
s += stringConstants[long1];
break;
case 0x1B:
case 0x1C:
nsSet = namespaceSetConstants[long1];
len = nsSet.length;
for (j = 0; j < len - 1; j++)
{
s += nsSet[j] + ",";
}
if (len > 0)
s += nsSet[len - 1] + ":";
s += "null";
break;
case 0x1D:
s += (typeName != null) ? typeName.toString() : "nullTypeName";
if (types != null)
{
for (int t = 0; t < types.length; t++)
s += (types[t] != null) ? types[t].toString() : "nullType";
}
else {
s += "no types";
}
}
return s;
}
}
class MethodInfo
{
int paramCount;
int returnType;
int[] params;
String name;
int kind;
int flags;
int optionCount;
int[] optionKinds;
int[] optionIndex;
int[] paramNames;
String className;
boolean sawTraits;
}
class LabelMgr
{
int index = 0;
HashMap<String, Integer> labels;
public LabelMgr()
{
labels = new HashMap<String, Integer>();
}
public String getLabelAt(int offset)
{
String key = Integer.toString(offset);
if (!labels.containsKey(key))
labels.put(key, new Integer(index++));
return "L" + labels.get(key).toString();
}
public boolean hasLabelAt(int offset)
{
String key = Integer.toString(offset);
return labels.containsKey(key);
}
}
}