diff --git a/README.md b/README.md index 589db90..0421bd1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ -# jxe2jar -Reverse conversion from Intel JXE format to Oracle JAR +# JXE2JAR + +Tool for reverse conversion from Intel JXE format to Oracle JAR. +Detailed info in doc/jxe2jar.pdf. + +## Dependencies +bitstring + +## Using +python JXE2JAR.py input.jxe output.jar + +## Thanks to @Black2Fan diff --git a/doc/jxe2jar.pdf b/doc/jxe2jar.pdf new file mode 100644 index 0000000..b2f091a Binary files /dev/null and b/doc/jxe2jar.pdf differ diff --git a/src/Bytecode.py b/src/Bytecode.py new file mode 100644 index 0000000..5d728af --- /dev/null +++ b/src/Bytecode.py @@ -0,0 +1,244 @@ +from Common import * + +import struct + +JBOpcode = enum( + JBnop=0x00, JBaconstnull=0x01, JBiconstm1=0x02, JBiconst0=0x03, JBiconst1=0x04, JBiconst2=0x05, + JBiconst3=0x06, JBiconst4=0x07, JBiconst5=0x08, JBlconst0=0x09, JBlconst1=0x0a, JBfconst0=0x0b, + JBfconst1=0x0c, JBfconst2=0x0d, JBdconst0=0x0e, JBdconst1=0x0f, JBbipush=0x10, JBsipush=0x11, + JBldc=0x12, JBldcw=0x13, JBldc2lw=0x14, JBiload=0x15, JBlload=0x16, JBfload=0x17, JBdload=0x18, + JBaload=0x19, JBiload0=0x1a, JBiload1=0x1b, JBiload2=0x1c, JBiload3=0x1d, JBlload0=0x1e, + JBlload1=0x1f, JBlload2=0x20, JBlload3=0x21, JBfload0=0x22, JBfload1=0x23, JBfload2=0x24, + JBfload3=0x25, JBdload0=0x26, JBdload1=0x27, JBdload2=0x28, JBdload3=0x29, JBaload0=0x2a, + JBaload1=0x2b, JBaload2=0x2c, JBaload3=0x2d, JBiaload=0x2e, JBlaload=0x2f, JBfaload=0x30, + JBdaload=0x31, JBaaload=0x32, JBbaload=0x33, JBcaload=0x34, JBsaload=0x35, JBistore=0x36, + JBlstore=0x37, JBfstore=0x38, JBdstore=0x39, JBastore=0x3a, JBistore0=0x3b, JBistore1=0x3c, + JBistore2=0x3d, JBistore3=0x3e, JBlstore0=0x3f, JBlstore1=0x40, JBlstore2=0x41, JBlstore3=0x42, + JBfstore0=0x43, JBfstore1=0x44, JBfstore2=0x45, JBfstore3=0x46, JBdstore0=0x47, JBdstore1=0x48, + JBdstore2=0x49, JBdstore3=0x4a, JBastore0=0x4b, JBastore1=0x4c, JBastore2=0x4d, JBastore3=0x4e, + JBiastore=0x4f, JBlastore=0x50, JBfastore=0x51, JBdastore=0x52, JBaastore=0x53, JBbastore=0x54, + JBcastore=0x55, JBsastore=0x56, JBpop=0x57, JBpop2=0x58, JBdup=0x59, JBdupx1=0x5a, JBdupx2=0x5b, + JBdup2=0x5c, JBdup2x1=0x5d, JBdup2x2=0x5e, JBswap=0x5f, JBiadd=0x60, JBladd=0x61, JBfadd=0x62, + JBdadd=0x63, JBisub=0x64, JBlsub=0x65, JBfsub=0x66, JBdsub=0x67, JBimul=0x68, JBlmul=0x69, + JBfmul=0x6a, JBdmul=0x6b, JBidiv=0x6c, JBldiv=0x6d, JBfdiv=0x6e, JBddiv=0x6f, JBirem=0x70, + JBlrem=0x71, JBfrem=0x72, JBdrem=0x73, JBineg=0x74, JBlneg=0x75, JBfneg=0x76, JBdneg=0x77, + JBishl=0x78, JBlshl=0x79, JBishr=0x7a, JBlshr=0x7b, JBiushr=0x7c, JBlushr=0x7d, JBiand=0x7e, + JBland=0x7f, JBior=0x80, JBlor=0x81, JBixor=0x82, JBlxor=0x83, JBiinc=0x84, JBi2l=0x85, + JBi2f=0x86, JBi2d=0x87, JBl2i=0x88, JBl2f=0x89, JBl2d=0x8a, JBf2i=0x8b, JBf2l=0x8c, JBf2d=0x8d, + JBd2i=0x8e, JBd2l=0x8f, JBd2f=0x90, JBi2b=0x91, JBi2c=0x92, JBi2s=0x93, JBlcmp=0x94, JBfcmpl=0x95, + JBfcmpg=0x96, JBdcmpl=0x97, JBdcmpg=0x98, JBifeq=0x99, JBifne=0x9a, JBiflt=0x9b, JBifge=0x9c, + JBifgt=0x9d, JBifle=0x9e, JBificmpeq=0x9f, JBificmpne=0xa0, JBificmplt=0xa1, JBificmpge=0xa2, + JBificmpgt=0xa3, JBificmple=0xa4, JBifacmpeq=0xa5, JBifacmpne=0xa6, JBgoto=0xa7, JBjsr=0xa8, JBret=0xa9, + JBtableswitch=0xaa, JBlookupswitch=0xab, JBreturn0=0xac, JBreturn1=0xad, JBreturn2=0xae, JBsyncReturn0=0xaf, + JBsyncReturn1=0xb0, JBsyncReturn2=0xb1, JBgetstatic=0xb2, JBputstatic=0xb3, JBgetfield=0xb4, JBputfield=0xb5, + JBinvokevirtual=0xb6, JBinvokespecial=0xb7, JBinvokestatic=0xb8, JBinvokeinterface=0xb9, JBnew=0xbb, + JBnewarray=0xbc, JBanewarray=0xbd, JBarraylength=0xbe, JBathrow=0xbf, JBcheckcast=0xc0, + JBinstanceof=0xc1, JBmonitorenter=0xc2, JBmonitorexit=0xc3, JBmultianewarray=0xc5, JBifnull=0xc6, + JBifnonnull=0xc7, JBgotow=0xc8, JBbreakpoint=0xca, JBiloadw=0xcb, JBlloadw=0xcc, JBfloadw=0xcd, + JBdloadw=0xce, JBaloadw=0xcf, JBistorew=0xd0, JBlstorew=0xd1, JBfstorew=0xd2, JBdstorew=0xd3, + JBastorew=0xd4, JBiincw=0xd5, JBaload0getfield=0xd7, JBreturnFromConstructor=0xe4, + JBgenericReturn=0xe5, JBinvokeinterface2=0xe7, JBreturnToMicroJIT=0xf3, JBretFromNative0=0xf4, + JBretFromNative1=0xf5, JBretFromNativeF=0xf6, JBretFromNativeD=0xf7, JBretFromNativeJ=0xf8, + JBldc2dw=0xf9, JBasyncCheck=0xfa, JBimpdep1=0xfe, JBimpdep2=0xff +) + +def transform_bytecode(bytecode, cp): + i = 0 + new_cp_transform = {} + new_bytecode = bytearray() + while i < len(bytecode): + opcode = bytecode[i] + if opcode in ( + JBOpcode.JBgetstatic, JBOpcode.JBputstatic, JBOpcode.JBgetfield, + JBOpcode.JBputfield, JBOpcode.JBinvokevirtual, JBOpcode.JBinvokespecial, + JBOpcode.JBinvokestatic, JBOpcode.JBnew, + JBOpcode.JBanewarray, JBOpcode.JBcheckcast, JBOpcode.JBinstanceof, + ): + new_bytecode.append(opcode) + index = struct.unpack('H', new_index + 1) + new_bytecode += tmp + i += 3 + elif opcode in (JBOpcode.JBldcw,): + new_bytecode.append(opcode) + index = struct.unpack('H', new_index + 1) + new_bytecode += tmp + i += 3 + elif opcode in (JBOpcode.JBldc2lw,): + index = struct.unpack('H', new_index + 1) + new_cp_transform[new_index]= '\x05' + new_bytecode += tmp + else: + new_bytecode.append(JBOpcode.JBldcw) + if cp.check_transform(index): + transform = cp.get_transform(index) + new_index = transform['new_index'] + else: + # TODO very dirty hack, because we incorrectly parse constant pool used in 1 case + new_index = 0 + tmp = struct.pack('>H', new_index + 1) + new_bytecode += tmp + i += 3 + elif opcode in (JBOpcode.JBldc2dw,): + new_bytecode.append(JBOpcode.JBldc2lw) + index = struct.unpack('H', new_index + 1) + new_cp_transform[new_index] = '\x06' + new_bytecode += tmp + i += 3 + elif opcode in ( + JBOpcode.JBiloadw, JBOpcode.JBlloadw, + JBOpcode.JBfloadw, JBOpcode.JBdloadw, JBOpcode.JBaloadw, JBOpcode.JBistorew, + JBOpcode.JBlstorew, JBOpcode.JBfstorew, JBOpcode.JBdstorew, JBOpcode.JBastorew, + JBOpcode.JBiincw, + ): + raise NotImplementedError(hex(opcode)) + elif opcode in ( + JBOpcode.JBsipush, JBOpcode.JBifeq, JBOpcode.JBifne, JBOpcode.JBiflt, JBOpcode.JBifge, + JBOpcode.JBifgt, JBOpcode.JBifle, JBOpcode.JBificmpeq, JBOpcode.JBificmpne, + JBOpcode.JBificmplt, JBOpcode.JBificmpge, JBOpcode.JBificmpgt, + JBOpcode.JBificmple, JBOpcode.JBifacmpeq, JBOpcode.JBifacmpne, JBOpcode.JBgoto, + JBOpcode.JBjsr, JBOpcode.JBifnull, JBOpcode.JBifnonnull, + ): + new_bytecode.append(opcode) + index = struct.unpack('H', index) + new_bytecode += tmp + i += 3 + elif opcode in (JBOpcode.JBaload0getfield,): + new_bytecode.append(JBOpcode.JBaload0) + i += 1 + elif opcode in ( + JBOpcode.JBreturn0, JBOpcode.JBsyncReturn0 + ): + # JBreturn0 -> return (0xb1) + # Used only if function return void + new_bytecode.append(0xb1) + i += 1 + elif opcode in (JBOpcode.JBreturn1, JBOpcode.JBsyncReturn1): + # JBreturn1 -> areturn (0xb0) + # Used only after push on stack + new_bytecode.append(0xb0) + i += 1 + elif opcode in (JBOpcode.JBinvokeinterface2,): + # JBinvokeinterface2 -> invokeinterface + # Usually placed as JBinvokeinterface2 JBnop JBinvokeinterface + # invokeinterface in Oracle get 4 bytes but j9 get 2 + # JBinvokeinterface2 JBnop correlate with this to fix this misalign + new_bytecode.append(JBOpcode.JBinvokeinterface) + index = struct.unpack('H', new_index + 1) + new_cp_transform[index] = '\x0b' + new_bytecode += tmp + new_bytecode.append(0) + new_bytecode.append(0) + i += 5 + elif opcode in (JBOpcode.JBinvokeinterface,): + raise NotImplementedError + elif opcode in (JBOpcode.JBldc,): + new_bytecode.append(opcode) + index = bytecode[i + 1] + transform = cp.get_transform(index) + new_index = transform['new_index'] + new_bytecode.append(new_index + 1) + i += 2 + elif opcode in ( + JBOpcode.JBbipush, JBOpcode.JBnewarray, + JBOpcode.JBiload, JBOpcode.JBlload, JBOpcode.JBfload, JBOpcode.JBdload, + JBOpcode.JBaload, JBOpcode.JBistore, JBOpcode.JBlstore, JBOpcode.JBfstore, + JBOpcode.JBdstore, JBOpcode.JBastore, JBOpcode.JBret + ): + new_bytecode.append(opcode) + new_bytecode.append(bytecode[i + 1]) + i += 2 + elif opcode in (JBOpcode.JBiinc,): + new_bytecode.append(opcode) + new_bytecode.append(bytecode[i + 1]) + new_bytecode.append(bytecode[i + 2]) + i += 3 + elif opcode in (JBOpcode.JBtableswitch,): + new_bytecode.append(opcode) + padding = ((i + 1) % 4) + padding = padding if padding == 0 else (4 - padding) + for j in xrange(padding): + new_bytecode.append(0x0) + i += padding + 1 + default = struct.unpack('I', default) + new_bytecode += tmp + i += 4 + low = struct.unpack('i', low) + new_bytecode += tmp + i += 4 + high = struct.unpack('i', high) + new_bytecode += tmp + try: + for j in xrange(high - low + 1): + i += 4 + left = struct.unpack('I', left) + new_bytecode += tmp + except OverflowError as err: + raise err + i += 4 + elif opcode in (JBOpcode.JBlookupswitch,): + new_bytecode.append(opcode) + padding = ((i + 1) % 4) + padding = padding if padding == 0 else (4 - padding) + for j in xrange(padding): + new_bytecode.append(0x0) + i += padding + 1 + default = struct.unpack('I', default) + new_bytecode += tmp + i += 4 + n = struct.unpack('I', n) + new_bytecode += tmp + for j in xrange(n): + i += 4 + left = struct.unpack('I', left) + new_bytecode += tmp + i += 4 + right = struct.unpack('I', right) + new_bytecode += tmp + i += 4 + elif opcode in (JBOpcode.JBmultianewarray,): + new_bytecode.append(opcode) + index = struct.unpack('H', new_index + 1) + new_bytecode += tmp + new_bytecode.append(bytecode[i + 3]) + i += 4 + elif opcode in (JBOpcode.JBgotow,): + new_bytecode.append(opcode) + value = struct.unpack('I', value) + new_bytecode += tmp + i += 5 + else: + new_bytecode.append(opcode) + i += 1 + for index in new_cp_transform: + cp.apply_transform(index, new_cp_transform[index]) + return new_bytecode \ No newline at end of file diff --git a/src/Common.py b/src/Common.py new file mode 100644 index 0000000..0aaf7b9 --- /dev/null +++ b/src/Common.py @@ -0,0 +1,143 @@ +import os +import os.path +import errno +import StringIO +import bitstring + +class StreamCursor(object): + def __init__(self, stream, pos): + self._stream_ = stream + self._new_pos_ = pos + self._old_pos_ = None + + def __enter__(self): + self._old_pos_ = self._stream_.get() + if self._new_pos_ < 0 or self._new_pos_ > self._stream_.len: + raise EOFError + self._stream_.set(self._new_pos_) + + def __exit__(self, exc_type, exc_val, exc_tb): + self._stream_.set(self._old_pos_) + +class ReaderStream(object): + def __init__(self, obj): + if isinstance(obj, file): + self._file_object_ = obj + self._bit_stream_ = bitstring.BitStream(self._file_object_) + elif isinstance(obj, bitstring.BitArray): + self._bit_stream_ = bitstring.BitStream() + self._bit_stream_._append(obj) + + def get(self): + return self._bit_stream_.bytepos + + def set(self, pos): + self._bit_stream_.bytepos = pos + + def read_bytes(self, length): + return self._bit_stream_.read('bytes:{0}'.format(length)) + + def read_u8(self): + return self._bit_stream_.read('uintle:8') + + def read_u16(self): + return self._bit_stream_.read('uintle:16') + + def read_u32(self): + return self._bit_stream_.read('uintle:32') + + def read_i8(self): + return self._bit_stream_.read('intle:8') + + def read_i16(self): + return self._bit_stream_.read('intle:16') + + def read_i32(self): + return self._bit_stream_.read('intle:32') + + def read_string(self): + length = self.read_u16() + return self.read_bytes(length) + + def read_relative(self): + base = self.get() + ptr = self.read_i32() + return base + ptr + + def read_string_ref(self): + ptr = self.read_relative() + pos = self.get() + self.set(ptr) + value = self.read_string() + self.set(pos) + return value + + @property + def bytes(self): + return self._bit_stream_.bytes + + @property + def len(self): + return self._bit_stream_.length / 8 + + @property + def file_object(self): + return self._file_object_ + + @staticmethod + def bytes_to_stream(bytes): + return ReaderStream(bitstring.BitArray(bytes=bytes)) + +class WriterStream(object): + def __init__(self, file_object): + self._file_object_ = file_object + self._bit_stream_ = bitstring.BitStream() + + def write(self): + self._bit_stream_.tofile(self._file_object_) + + def write_raw_bytes(self, data): + return self._bit_stream_._append( + bitstring.BitArray(bytes=data) + ) + + def write_u8(self, value): + return self._bit_stream_._append( + bitstring.pack('uintbe:8', value) + ) + + def write_u16(self, value): + return self._bit_stream_._append( + bitstring.pack('uintbe:16', value) + ) + + def write_u32(self, value): + return self._bit_stream_._append( + bitstring.pack('uintbe:32', value) + ) + + def write_i8(self, value): + return self._bit_stream_._append( + bitstring.pack('intbe:8', value) + ) + + def write_i16(self, value): + return self._bit_stream_._append( + bitstring.pack('intbe:16', value) + ) + + def write_i32(self, value): + return self._bit_stream_._append( + bitstring.pack('intbe:32', value) + ) + +def enum(**enums): + return type('Enum', (), enums) + +def create_file_path(filepath): + if not os.path.exists(os.path.dirname(filepath)): + try: + os.makedirs(os.path.dirname(filepath)) + except OSError as exc: # Guard against race condition + if exc.errno != errno.EEXIST: + raise \ No newline at end of file diff --git a/src/ConstPool.py b/src/ConstPool.py new file mode 100644 index 0000000..3e36147 --- /dev/null +++ b/src/ConstPool.py @@ -0,0 +1,106 @@ +import struct +from Common import * + +CONST = enum( + Class = '\x07', + FieldRef = '\x09', + MethodRef = '\x0a', + InterfaceMethodRef = '\x0b', + String = '\x08', + Integer = '\x03', + Float = '\x04', + Long = '\x05', + Double = '\x06', + NameAndType = '\x0c', + Utf8 = '\x01' +) + +J9CONST = enum( + INT = 0, + STRING = 1, + CLASS = 2, + LONG = 3, + REF = 4 +) + +class ConstPool(object): + def __init__(self, romclass): + self.pool = [] + self.transform = {} + stack = [] + # self.pool.append([-1, None]) + for i, constant in enumerate(romclass.constant_pool): + if constant.type == J9CONST.INT: + index = len(self.pool) + self.pool.append([CONST.Integer, constant.value]) + self.transform[i] = {'new_index': index, 'type': CONST.Integer} + elif constant.type == J9CONST.LONG: + index = len(self.pool) + self.pool.append([CONST.Double, constant.value[::-1]]) + self.pool.append([-1, None]) + self.transform[i] = {'new_index': index, 'type': CONST.Double} + elif constant.type == J9CONST.STRING: + index = len(self.pool) + self.pool.append([CONST.String, '']) + stack.append((index, CONST.Utf8, struct.pack('>H', len(constant.value)) + constant.value)) + self.transform[i] = {'new_index': index, 'type': CONST.String} + elif constant.type == J9CONST.CLASS: + index = len(self.pool) + self.pool.append([CONST.Class, '']) + stack.append((index, CONST.Utf8, struct.pack('>H', len(constant.value)) + constant.value)) + self.transform[i] = {'new_index': index, 'type': CONST.Class} + elif constant.type == J9CONST.REF: + index = len(self.pool) + const_type = CONST.MethodRef if constant.descriptor.find('(') >= 0 else CONST.FieldRef + self.pool.append([const_type, '', '']) + stack.append((index, CONST.Class, struct.pack('>H', len(constant._class)) + constant._class)) + stack.append((index, CONST.NameAndType, struct.pack('>H', len(constant.name)) + constant.name, + struct.pack('>H', len(constant.descriptor)) + constant.descriptor)) + self.transform[i] = {'new_index': index, 'type': const_type} + for elem in stack: + cp_id = len(self.pool) + if elem[1] == CONST.Utf8: + self.pool.append([elem[1], elem[2]]) + if self.pool[elem[0]][1]: + self.pool[elem[0]][2] = struct.pack('>H', cp_id + 1) + else: + self.pool[elem[0]][1] = struct.pack('>H', cp_id + 1) + elif elem[1] == CONST.Class: + self.pool.append([elem[1], '']) + stack.append((cp_id, CONST.Utf8, elem[2])) + self.pool[elem[0]][1] = struct.pack('>H', cp_id + 1) + elif elem[1] == CONST.NameAndType: + self.pool.append([elem[1], '', '']) + stack.append((cp_id, CONST.Utf8, elem[2])) + stack.append((cp_id, CONST.Utf8, elem[3])) + self.pool[elem[0]][2] = struct.pack('>H', cp_id + 1) + + def add(self, type, value): + if type == CONST.Class: + index = len(self.pool) + self.pool.append([CONST.Utf8, struct.pack('>H', len(value)) + bytearray(value, 'utf8')]) + self.pool.append([CONST.Class, struct.pack('>H', index + 1)]) + return index + 2 + elif type == CONST.Utf8: + index = len(self.pool) + self.pool.append([CONST.Utf8, struct.pack('>H', len(value)) + bytearray(value, 'utf8')]) + return index + 1 + + def apply_transform(self, index, type): + self.pool[index][0] = type + + def check_transform(self, index, type=None): + return index in self.transform and (type and self.transform[index]['type'] == '\x06') + + def get_transform(self, index): + return self.transform[index] + + def write(self, stream): + stream.write_u16(len(self.pool) + 1) + for elem in self.pool: + if elem[0] == -1: + continue + stream.write_raw_bytes(elem[0]) + stream.write_raw_bytes(elem[1]) + if len(elem) > 2: + stream.write_raw_bytes(elem[2]) diff --git a/src/JXE.py b/src/JXE.py new file mode 100644 index 0000000..1984f34 --- /dev/null +++ b/src/JXE.py @@ -0,0 +1,279 @@ +import struct +from zipfile import ZipFile +from Common import * + +class J9ROMField(object): + def __init__(self, name, signature, access_flag): + super(J9ROMField, self).__init__() + self.name = name + self.signature = signature + self.access_flag = access_flag + + @staticmethod + def read(stream): + name = stream.read_string_ref() + signature = stream.read_string_ref() + access_flags = stream.read_u32() + if access_flags & 0x400000: + unknown1 = stream.read_u32() + if access_flags & 0x40000: + unknown2 = stream.read_u32() + if access_flags & 0x40000000: + unknown3 = stream.read_u32() + return J9ROMField(name, signature, access_flags) + +class J9ROMCatchException(object): + def __init__(self, start, end, handler, catch_type): + super(J9ROMCatchException, self).__init__() + self.start = start + self.end = end + self.handler = handler + self.catch_type = catch_type + + @staticmethod + def read(stream): + start = stream.read_u32() + end = stream.read_u32() + handler = stream.read_u32() + catch_type = stream.read_u32() + return J9ROMCatchException(start, end, handler, catch_type) + +class J9ROMThrowException(object): + def __init__(self, throw_type): + super(J9ROMThrowException, self).__init__() + self.throw_type = throw_type + + @staticmethod + def read(stream): + return J9ROMThrowException(stream.read_string_ref()) + +class J9ROMMethod(object): + def __init__(self, name, signature, modifier, max_stack, arg_count, temp_count, bytecode, catch_exceptions, throw_exceptions): + super(J9ROMMethod, self).__init__() + self.name = name + self.signature = signature + self.modifier = modifier + self.max_stack = max_stack + self.arg_count = arg_count + self.temp_count = temp_count + self.bytecode = bytecode + self.catch_exceptions = catch_exceptions + self.throw_exceptions = throw_exceptions + + @staticmethod + def read(stream): + name = stream.read_string_ref() + signature = stream.read_string_ref() + modifier = stream.read_u32() + use_bytecodesize_high = modifier & 0x00008000 + add_four1 = modifier & 0x02000000 + has_bytecode_extra = modifier & 0x00020000 + add_four2 = modifier & 0x00400000 + max_stack = stream.read_u16() + if modifier & 0x100: + arg_count = stream.read_u8() + temp_count = stream.read_u8() + stream.read_u8() + native_arg_count = stream.read_u8() + caught_exceptions = [] + thrown_exceptions = [] + print "Native method" + else: + bytecode_size_low = stream.read_u16() + bytecode_size_high = stream.read_u8() + arg_count = stream.read_u8() + temp_count = stream.read_u16() + bytecode_size = bytecode_size_low + if use_bytecodesize_high: + bytecode_size += bytecode_size_high << 16 + bytecode_size *= 4 + if add_four1: + bytecode_size += 4 + bytecode = stream.read_bytes(bytecode_size) + if has_bytecode_extra: + caught_exception_count = stream.read_u16() + thrown_exception_count = stream.read_u16() + caught_exceptions = [J9ROMCatchException.read(stream) for i in xrange(caught_exception_count)] + thrown_exceptions = [J9ROMThrowException.read(stream) for i in xrange(thrown_exception_count)] + else: + caught_exceptions = [] + thrown_exceptions = [] + if add_four2: + aot_addr = stream.read_u32() + return J9ROMMethod(name, signature, modifier, max_stack, arg_count, temp_count, bytecode, caught_exceptions, thrown_exceptions) + +class J9ROMInterface(object): + def __init__(self, name): + super(J9ROMInterface, self).__init__() + self.name = name + + @staticmethod + def read(stream): + name = stream.read_string_ref() + return J9ROMInterface(name) + +ConstType = enum( + INT = 0, + STRING = 1, + CLASS = 2, + LONG = 3, + REF = 4 +) + +class J9ROMConstant(object): + def __init__(self, type, value=None, _class=None, name=None, descriptor=None): + super(J9ROMConstant, self).__init__() + self.type = type + if type in (ConstType.INT, ConstType.STRING, ConstType.LONG): + self.value = value + elif type == ConstType.CLASS: + self.value = value + elif type == ConstType.REF: + self._class = _class + self.name = name + self.descriptor = descriptor + + @staticmethod + def read(stream, base): + pos = stream.get() + value = stream.read_u32() + type = stream.read_u32() + if type in (1, 2): + value = struct.unpack(' 0 else 0) + for exception in method.catch_exceptions + ], + 'attributes_count': 0, + 'attributes': [] + } + ] + } + ) + cp.write(stream) + stream.write_u16(romclass.access_flags & 0xffff) + stream.write_u16(class_name_id) + stream.write_u16(superclass_name_id) + stream.write_u16(len(interface_id_list)) + for elem in interface_id_list: + stream.write_u16(elem) + stream.write_u16(len(field_info_list)) + for field_info in field_info_list: + stream.write_u16(field_info['access_flags'] & 0xffff) + stream.write_u16(field_info['name_index']) + stream.write_u16(field_info['descriptor_index']) + stream.write_u16(field_info['attributes_count']) + if field_info['attributes_count']: + raise NotImplementedError() + stream.write_u16(len(method_info_list)) + for method_info in method_info_list: + stream.write_u16(method_info['access_flags'] & 0xffff) + stream.write_u16(method_info['name_index']) + stream.write_u16(method_info['descriptor_index']) + stream.write_u16(method_info['attributes_count']) + attribute = method_info['attributes'][0] + stream.write_u16(attribute['attribute_name_index']) + stream.write_u32(attribute['attribute_length']) + if (romclass.major, romclass.minor) < (45, 3): + stream.write_u8(attribute['max_stack']) + stream.write_u8(attribute['max_locals']) + stream.write_u16(attribute['code_length']) + else: + stream.write_u16(attribute['max_stack']) + stream.write_u16(attribute['max_locals']) + stream.write_u32(attribute['code_length']) + stream.write_raw_bytes(attribute['code']) + stream.write_u16(attribute['exception_table_length']) + for exception in attribute['exception_table']: + stream.write_u16(exception[0]) + stream.write_u16(exception[1]) + stream.write_u16(exception[2]) + stream.write_u16(exception[3]) + stream.write_u16(attribute['attributes_count']) + if attribute['attributes_count']: + raise NotImplementedError() + stream.write_u16(0) + +def create_class(romclass, jarfile): + class_name = romclass.class_name # .replace('/', '.') + class_file = '{0}.class'.format(class_name) + f = StringIO.StringIO() + stream = WriterStream(f) + dump_romclass(stream, romclass) + stream.write() + jarfile.writestr(class_file, f.getvalue()) + +def create_jar(jar_name, jxe, decompilation_check=True): + jarfile = zipfile.ZipFile(jar_name, 'w') + for romclass in jxe.image.classes: + create_class(romclass, jarfile) + +def process(jxe_name, jar_name): + with open(jxe_name, 'rb') as f: + stream = ReaderStream(f) + jxe = JXE.read(stream) + create_jar(jar_name, jxe) + +def main(): + jxe_name = sys.argv[1] + jar_name = sys.argv[2] + process(jxe_name, jar_name) + +if __name__ == '__main__': + main()