Asm

/* $Id$ */
/* Copyright (c) 2011-2022 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Devel Asm */
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <System.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "Asm.h"
/* Java */
/* private */
/* types */
struct _AsmArchPlugin
{
AsmArchPluginHelper * helper;
};
/* variables */
static AsmArchDefinition const _java_definition =
{
"java", ASM_ARCH_ENDIAN_BIG, 32, 8, 0
};
static AsmArchRegister const _java_registers[] =
{
#include "null.reg"
};
#define OP1F (8 << AOD_SIZE)
#define OP_U8 AO_IMMEDIATE(0, 8, 0)
#define OP_U16 AO_IMMEDIATE(0, 16, 0)
#define OP_U16_STR AO_IMMEDIATE(0, 16, AOI_REFERS_STRING)
#define OP_U16_FUNC AO_IMMEDIATE(0, 16, AOI_REFERS_FUNCTION)
#define OP_S32 AO_IMMEDIATE(AOF_SIGNED, 32, 0)
#define OP_U32 AO_IMMEDIATE(0, 32, 0)
static AsmArchInstruction const _java_instructions[] =
{
{ "aaload", 0x32, OP1F, AO_0() },
{ "aastore", 0x53, OP1F, AO_0() },
{ "aconst_null",0x01, OP1F, AO_0() },
{ "aload", 0x19, OP1F, AO_1(OP_U8) },
{ "aload_0", 0x2a, OP1F, AO_0() },
{ "aload_1", 0x2b, OP1F, AO_0() },
{ "aload_2", 0x2c, OP1F, AO_0() },
{ "aload_3", 0x2d, OP1F, AO_0() },
{ "areturn", 0xb0, OP1F, AO_0() },
{ "arraylength",0xbe, OP1F, AO_0() },
{ "astore", 0x3a, OP1F, AO_1(OP_U8) },
{ "astore_0", 0x4b, OP1F, AO_0() },
{ "astore_1", 0x4c, OP1F, AO_0() },
{ "astore_2", 0x4d, OP1F, AO_0() },
{ "astore_3", 0x4e, OP1F, AO_0() },
{ "athrow", 0xbf, OP1F, AO_0() },
{ "baload", 0x33, OP1F, AO_0() },
{ "bastore", 0x54, OP1F, AO_0() },
{ "bipush", 0x10, OP1F, AO_1(OP_U8) },
{ "caload", 0x34, OP1F, AO_0() },
{ "castore", 0x55, OP1F, AO_0() },
{ "checkcast", 0xc0, OP1F, AO_1(OP_U16) },
{ "d2f", 0x90, OP1F, AO_0() },
{ "d2i", 0x8e, OP1F, AO_0() },
{ "d2l", 0x8f, OP1F, AO_0() },
{ "dadd", 0x63, OP1F, AO_0() },
{ "daload", 0x31, OP1F, AO_0() },
{ "dastore", 0x52, OP1F, AO_0() },
{ "dcmpg", 0x98, OP1F, AO_0() },
{ "dcmpl", 0x97, OP1F, AO_0() },
{ "dconst_0", 0x0e, OP1F, AO_0() },
{ "dconst_1", 0x0f, OP1F, AO_0() },
{ "ddiv", 0x6f, OP1F, AO_0() },
{ "dload", 0x18, OP1F, AO_1(OP_U8) },
{ "dload_0", 0x26, OP1F, AO_0() },
{ "dload_1", 0x27, OP1F, AO_0() },
{ "dload_2", 0x28, OP1F, AO_0() },
{ "dload_3", 0x29, OP1F, AO_0() },
{ "dmul", 0x6b, OP1F, AO_0() },
{ "dneg", 0x77, OP1F, AO_0() },
{ "drem", 0x73, OP1F, AO_0() },
{ "dreturn", 0xaf, OP1F, AO_0() },
{ "dstore", 0x39, OP1F, AO_1(OP_U8) },
{ "dstore_0", 0x47, OP1F, AO_0() },
{ "dstore_1", 0x48, OP1F, AO_0() },
{ "dstore_2", 0x49, OP1F, AO_0() },
{ "dstore_3", 0x4a, OP1F, AO_0() },
{ "dsub", 0x67, OP1F, AO_0() },
{ "dup", 0x59, OP1F, AO_0() },
{ "dup_x1", 0x5a, OP1F, AO_0() },
{ "dup_x2", 0x5b, OP1F, AO_0() },
{ "dup2", 0x5c, OP1F, AO_0() },
{ "dup2_x1", 0x5d, OP1F, AO_0() },
{ "dup2_x2", 0x5e, OP1F, AO_0() },
{ "f2d", 0x8d, OP1F, AO_0() },
{ "f2i", 0x8b, OP1F, AO_0() },
{ "f2l", 0x8c, OP1F, AO_0() },
{ "fadd", 0x62, OP1F, AO_0() },
{ "faload", 0x30, OP1F, AO_0() },
{ "fastore", 0x51, OP1F, AO_0() },
{ "fcmpg", 0x96, OP1F, AO_0() },
{ "fcmpl", 0x95, OP1F, AO_0() },
{ "fconst_0", 0x0b, OP1F, AO_0() },
{ "fconst_1", 0x0c, OP1F, AO_0() },
{ "fconst_2", 0x0d, OP1F, AO_0() },
{ "fdiv", 0x6e, OP1F, AO_0() },
{ "fload", 0x17, OP1F, AO_1(OP_U8) },
{ "fload_0", 0x22, OP1F, AO_0() },
{ "fload_1", 0x23, OP1F, AO_0() },
{ "fload_2", 0x24, OP1F, AO_0() },
{ "fload_3", 0x25, OP1F, AO_0() },
{ "fmul", 0x6a, OP1F, AO_0() },
{ "fneg", 0x76, OP1F, AO_0() },
{ "frem", 0x72, OP1F, AO_0() },
{ "freturn", 0xae, OP1F, AO_0() },
{ "fstore_0", 0x43, OP1F, AO_0() },
{ "fstore_1", 0x44, OP1F, AO_0() },
{ "fstore_2", 0x45, OP1F, AO_0() },
{ "fstore_3", 0x46, OP1F, AO_0() },
{ "fsub", 0x66, OP1F, AO_0() },
{ "getfield", 0xb4, OP1F, AO_1(OP_U16_STR) },
{ "getstatic", 0xb2, OP1F, AO_1(OP_U16_STR) },
{ "goto", 0xa7, OP1F, AO_1(OP_U16) },
{ "goto_w", 0xc8, OP1F, AO_1(OP_U32) },
{ "i2b", 0x91, OP1F, AO_0() },
{ "i2c", 0x92, OP1F, AO_0() },
{ "i2d", 0x87, OP1F, AO_0() },
{ "i2f", 0x86, OP1F, AO_0() },
{ "i2l", 0x85, OP1F, AO_0() },
{ "i2s", 0x93, OP1F, AO_0() },
{ "iadd", 0x60, OP1F, AO_0() },
{ "iaload", 0x2e, OP1F, AO_0() },
{ "iand", 0x7e, OP1F, AO_0() },
{ "iastore", 0x4f, OP1F, AO_0() },
{ "iconst_m1", 0x02, OP1F, AO_0() },
{ "iconst_0", 0x03, OP1F, AO_0() },
{ "iconst_1", 0x04, OP1F, AO_0() },
{ "iconst_2", 0x05, OP1F, AO_0() },
{ "iconst_3", 0x06, OP1F, AO_0() },
{ "iconst_4", 0x07, OP1F, AO_0() },
{ "iconst_5", 0x08, OP1F, AO_0() },
{ "idiv", 0x6c, OP1F, AO_0() },
{ "if_acmpeq", 0xa5, OP1F, AO_1(OP_U16) },
{ "if_acmpne", 0xa6, OP1F, AO_1(OP_U16) },
{ "if_icmpeq", 0x9f, OP1F, AO_1(OP_U16) },
{ "if_icmpne", 0xa0, OP1F, AO_1(OP_U16) },
{ "if_icmplt", 0xa1, OP1F, AO_1(OP_U16) },
{ "if_icmpge", 0xa2, OP1F, AO_1(OP_U16) },
{ "if_icmpgt", 0xa3, OP1F, AO_1(OP_U16) },
{ "if_icmple", 0xa4, OP1F, AO_1(OP_U16) },
{ "ifeq", 0x99, OP1F, AO_1(OP_U16) },
{ "ifne", 0x9a, OP1F, AO_1(OP_U16) },
{ "iflt", 0x9b, OP1F, AO_1(OP_U16) },
{ "ifge", 0x9c, OP1F, AO_1(OP_U16) },
{ "ifgt", 0x9d, OP1F, AO_1(OP_U16) },
{ "ifle", 0x9e, OP1F, AO_1(OP_U16) },
{ "ifnonnull", 0xc7, OP1F, AO_1(OP_U16) },
{ "ifnull", 0xc6, OP1F, AO_1(OP_U16) },
{ "iinc", 0x84, OP1F, AO_2(OP_U8, OP_U8) },
{ "iload", 0x15, OP1F, AO_1(OP_U8) },
{ "iload_0", 0x1a, OP1F, AO_0() },
{ "iload_1", 0x1b, OP1F, AO_0() },
{ "iload_2", 0x1c, OP1F, AO_0() },
{ "iload_3", 0x1d, OP1F, AO_0() },
{ "impdep1", 0xfe, OP1F, AO_0() },
{ "impdep2", 0xff, OP1F, AO_0() },
{ "imul", 0x68, OP1F, AO_0() },
{ "ineg", 0x74, OP1F, AO_0() },
{ "instanceof", 0xc1, OP1F, AO_1(OP_U16_FUNC) },
{ "invokeinterface",0xb9,OP1F,AO_2(OP_U16_FUNC, OP_U8) },
{ "invokespecial",0xb7, OP1F, AO_1(OP_U16_FUNC) },
{ "invokestatic",0xb8, OP1F, AO_1(OP_U16_FUNC) },
{ "invokevirtual",0xb6, OP1F, AO_1(OP_U16_FUNC) },
{ "ior", 0x80, OP1F, AO_0() },
{ "irem", 0x70, OP1F, AO_0() },
{ "ireturn", 0xac, OP1F, AO_0() },
{ "ishl", 0x78, OP1F, AO_0() },
{ "ishr", 0x7a, OP1F, AO_0() },
{ "istore", 0x36, OP1F, AO_1(OP_U8) },
{ "istore_0", 0x3b, OP1F, AO_0() },
{ "istore_1", 0x3c, OP1F, AO_0() },
{ "istore_2", 0x3d, OP1F, AO_0() },
{ "istore_3", 0x3e, OP1F, AO_0() },
{ "isub", 0x64, OP1F, AO_0() },
{ "iushr", 0x7c, OP1F, AO_0() },
{ "ixor", 0x82, OP1F, AO_0() },
{ "jsr", 0xa8, OP1F, AO_1(OP_U16) },
{ "jsr_w", 0xc9, OP1F, AO_1(OP_U32) },
{ "l2d", 0x8a, OP1F, AO_0() },
{ "l2f", 0x89, OP1F, AO_0() },
{ "l2i", 0x88, OP1F, AO_0() },
{ "ladd", 0x61, OP1F, AO_0() },
{ "laload", 0x2f, OP1F, AO_0() },
{ "land", 0x7f, OP1F, AO_0() },
{ "lastore", 0x50, OP1F, AO_0() },
{ "lcmp", 0x94, OP1F, AO_0() },
{ "lconst_0", 0x09, OP1F, AO_0() },
{ "lconst_1", 0x0a, OP1F, AO_0() },
{ "ldc", 0x12, OP1F, AO_1(OP_U8) },
{ "ldc_w", 0x13, OP1F, AO_1(OP_U16) },
{ "ldc2_w", 0x14, OP1F, AO_1(OP_U16) },
{ "ldiv", 0x6d, OP1F, AO_0() },
{ "lload", 0x16, OP1F, AO_1(OP_U8) },
{ "lload_0", 0x1e, OP1F, AO_0() },
{ "lload_1", 0x1f, OP1F, AO_0() },
{ "lload_2", 0x20, OP1F, AO_0() },
{ "lload_3", 0x21, OP1F, AO_0() },
{ "lmul", 0x69, OP1F, AO_0() },
{ "lneg", 0x75, OP1F, AO_0() },
{ "lor", 0x81, OP1F, AO_0() },
{ "lrem", 0x71, OP1F, AO_0() },
{ "lreturn", 0xad, OP1F, AO_0() },
{ "lookupswitch",0xab, OP1F, AO_0() },
{ "lshl", 0x79, OP1F, AO_0() },
{ "lshr", 0x7b, OP1F, AO_0() },
{ "lstore", 0x37, OP1F, AO_1(OP_U8) },
{ "lstore_0", 0x3f, OP1F, AO_0() },
{ "lstore_1", 0x40, OP1F, AO_0() },
{ "lstore_2", 0x41, OP1F, AO_0() },
{ "lstore_3", 0x42, OP1F, AO_0() },
{ "lsub", 0x65, OP1F, AO_0() },
{ "lushr", 0x7d, OP1F, AO_0() },
{ "lxor", 0x83, OP1F, AO_0() },
{ "monitorenter",0xc2, OP1F, AO_0() },
{ "monitorexit",0xc3, OP1F, AO_0() },
{ "multianewarray",0xc5,OP1F, AO_2(OP_U16, OP_U8) },
{ "new", 0xbb, OP1F, AO_1(OP_U16_STR) },
{ "newarray", 0xbb, OP1F, AO_1(OP_U8) },
{ "nop", 0x00, OP1F, AO_0() },
{ "pop", 0x57, OP1F, AO_0() },
{ "pop2", 0x58, OP1F, AO_0() },
{ "putfield", 0xb5, OP1F, AO_1(OP_U16_STR) },
{ "putstatic", 0xb3, OP1F, AO_1(OP_U16_STR) },
{ "ret", 0xa9, OP1F, AO_1(OP_U8) },
{ "return", 0xb1, OP1F, AO_0() },
{ "saload", 0x35, OP1F, AO_0() },
{ "sastore", 0x56, OP1F, AO_0() },
{ "sipush", 0x11, OP1F, AO_1(OP_U16) },
{ "swap", 0x5f, OP1F, AO_0() },
{ "tableswitch",0xaa, OP1F, AO_3(OP_U32, OP_S32, OP_S32) },
{ "wide", 0xc4, OP1F, AO_2(OP_U8, OP_U16) },
{ "wide", 0xc4, OP1F, AO_3(OP_U8, OP_U8, OP_U16) },
{ "xxxunusedxxx",0xba, OP1F, AO_0() },
#include "common.ins"
#include "null.ins"
};
/* prototypes */
/* plug-in */
static AsmArchPlugin * _java_init(AsmArchPluginHelper * helper);
static void _java_destroy(AsmArchPlugin * plugin);
static int _java_encode(AsmArchPlugin * plugin,
AsmArchPrefix const * prefix,
AsmArchInstruction const * instruction,
AsmArchInstructionCall const * call);
static int _java_decode(AsmArchPlugin * plugin, AsmArchInstructionCall * call);
/* public */
/* variables */
AsmArchPluginDefinition arch_plugin =
{
"java",
"Java bytecode",
LICENSE_GNU_LGPL3_FLAGS,
&_java_definition,
_java_registers,
NULL,
_java_instructions,
_java_init,
_java_destroy,
_java_encode,
_java_decode
};
/* private */
/* functions */
/* plug-in */
/* java_init */
static AsmArchPlugin * _java_init(AsmArchPluginHelper * helper)
{
AsmArchPlugin * plugin;
if((plugin = object_new(sizeof(*plugin))) == NULL)
return NULL;
plugin->helper = helper;
return plugin;
}
/* java_destroy */
static void _java_destroy(AsmArchPlugin * plugin)
{
object_delete(plugin);
}
/* java_encode */
static int _java_encode(AsmArchPlugin * plugin,
AsmArchPrefix const * prefix,
AsmArchInstruction const * instruction,
AsmArchInstructionCall const * call)
{
AsmArchPluginHelper * helper = plugin->helper;
size_t i;
AsmArchOperandDefinition definitions[3];
AsmArchOperand const * ao;
uint8_t u8;
uint16_t u16;
uint32_t u32;
if(prefix != NULL)
return -error_set_code(1, "%s: %s",
helper->get_filename(helper->arch),
"Prefixes not supported for this architecture");
if((helper->write(helper->arch, &instruction->opcode, 1)) != 1)
return -1;
/* FIXME tableswitch may need some padding */
definitions[0] = instruction->op1;
definitions[1] = instruction->op2;
definitions[2] = instruction->op3;
for(i = 0; i < call->operands_cnt; i++)
{
ao = &call->operands[i];
if(AO_GET_TYPE(ao->definition) != AOT_IMMEDIATE)
return -error_set_code(1, "%s", "Not implemented");
if(AO_GET_SIZE(definitions[i]) == 8)
{
u8 = ao->value.immediate.value;
if(helper->write(helper->arch, &u8, 1) != 1)
return -1;
}
else if(AO_GET_SIZE(definitions[i]) == 16)
{
u16 = _htob16(ao->value.immediate.value);
if(helper->write(helper->arch, &u16, 2) != 2)
return -1;
}
else if(AO_GET_SIZE(definitions[i]) == 32)
{
u32 = _htob32(ao->value.immediate.value);
if(helper->write(helper->arch, &u32, 4) != 4)
return -1;
}
else
return -error_set_code(1, "%s", "Size not implemented");
}
return 0;
}
/* java_decode */
static int _java_decode(AsmArchPlugin * plugin, AsmArchInstructionCall * call)
{
AsmArchPluginHelper * helper = plugin->helper;
uint8_t u8;
AsmArchInstruction const * ai;
ssize_t s;
size_t i;
AsmArchOperand * ao;
uint16_t u16;
uint32_t u32;
AsmString * as;
uint32_t begin;
uint32_t end;
if(helper->read(helper->arch, &u8, sizeof(u8)) != sizeof(u8))
return -1;
if((ai = helper->get_instruction_by_opcode(helper->arch, 8, u8))
== NULL)
{
call->name = "db";
call->operands[0].definition = AO_IMMEDIATE(0, 8, 0);
call->operands[0].value.immediate.name = NULL;
call->operands[0].value.immediate.value = u8;
call->operands[0].value.immediate.negative = 0;
call->operands_cnt = 1;
return 0;
}
call->name = ai->name;
/* tableswitch may be followed by padding */
if(ai->opcode == 0xaa && (s = call->offset % 4) > 0
&& helper->read(helper->arch, &u32, s) != s)
return -1;
call->operands[0].definition = ai->op1;
call->operands[1].definition = ai->op2;
call->operands[2].definition = ai->op3;
for(i = 0; i < 3 && AO_GET_TYPE(call->operands[i].definition)
!= AOT_NONE; i++)
{
ao = &call->operands[i];
if(AO_GET_TYPE(ao->definition) != AOT_IMMEDIATE)
/* XXX should there be more types? */
return -error_set_code(1, "%s", "Not implemented");
if(AO_GET_SIZE(ao->definition) == 8)
{
if(helper->read(helper->arch, &u8, 1) != 1)
return -1;
ao->value.immediate.value = u8;
}
else if(AO_GET_SIZE(ao->definition) == 16)
{
if(helper->read(helper->arch, &u16, 2) != 2)
return -1;
u16 = _htob16(u16);
ao->value.immediate.value = u16;
}
else if(AO_GET_SIZE(ao->definition) == 32)
{
if(helper->read(helper->arch, &u32, 4) != 4)
return -1;
u32 = _htob32(u32);
ao->value.immediate.value = u32;
}
else
return -error_set_code(1, "%s", "Size not implemented");
ao->value.immediate.name = NULL;
ao->value.immediate.negative = 0;
switch(AO_GET_VALUE(ao->definition))
{
case AOI_REFERS_FUNCTION:
case AOI_REFERS_STRING:
as = helper->get_string_by_id(helper->arch,
ao->value.immediate.value);
if(as != NULL)
ao->value.immediate.name = as->name;
ao->value.immediate.negative = 0;
break;
}
}
call->operands_cnt = i;
/* tableswitch may be followed by offsets */
if(ai->opcode == 0xaa)
{
for(begin = call->operands[1].value.immediate.value,
end = call->operands[2].value.immediate.value;
begin <= end; begin++)
if(helper->read(helper->arch, &u32, sizeof(u32))
!= (ssize_t)sizeof(u32))
return -1;
}
return 0;
}