Add anal-plugin for gb

This commit is contained in:
condret 2013-12-11 16:00:36 +01:00 committed by pancake
parent 720488d68f
commit 7ce158acd3
5 changed files with 528 additions and 1 deletions

View File

@ -10,7 +10,7 @@ all: ${ALL_TARGETS} ;
ALL_TARGETS=
# TODO: rename to enabled plugins
ARCHS=x86_im.mk x86_udis.mk x86_simple.mk ppc.mk arm.mk avr.mk csr.mk dalvik.mk sh.mk ebc.mk
ARCHS=x86_im.mk x86_udis.mk x86_simple.mk ppc.mk arm.mk avr.mk csr.mk dalvik.mk sh.mk ebc.mk gb.mk
include $(ARCHS)
clean:

513
libr/anal/p/anal_gb.c Normal file
View File

@ -0,0 +1,513 @@
/* radare - LGPL - Copyright 2012 - pancake<nopcode.org>
2013 - condret */
/*
this file was based on anal_i8080.c
Todo(for Condret): 1. Implement all MBC's and detect Bankswitches
2. Trace all Data copied to OAM and VRAM (and add a command for converting the OAM/VRAM to a pngfile,
so that we can produce snapshots of the gb-screen for tracing sprites)
3. Payloads for gameboy
*/
#include <string.h>
#include <r_types.h>
#include <r_lib.h>
#include <r_asm.h>
#include <r_anal.h>
#include "../../asm/arch/gb/gbdis.c"
void meta_gb_hardware_cmt(RMeta *m, const ut8 hw, ut64 addr) {
switch(hw)
{
case 0:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "JOYPAD");
break;
case 1:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "Serial tranfer data");
break;
case 2:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "Serial tranfer data - Ctl");
break;
case 4:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "DIV");
break;
case 5:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "TIMA");
break;
case 6:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "TMA");
break;
case 7:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "TAC");
break;
case 0x0f:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "Interrupt Flag"); //TODO: save in sdb for halt
break;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1a:
case 0x1b:
case 0x1c:
case 0x1d:
case 0x1e:
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "SOUND");
break;
case 0x30:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "Wave Pattern RAM/SOUND");
break;
case 0x40:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "LCDC");
break;
case 0x41:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "LCDC - STAT");
break;
case 0x42:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "LCDC - Scroll y");
break;
case 0x43:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "LCDC - Scroll x");
break;
case 0x44:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "LCDC - y cord");
break;
case 0x45:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "LCDC - y cord cmp");
break;
case 0x46:
r_meta_set_string(m, R_META_TYPE_COMMENT, addr, "DMA");
break;
}
}
static int gb_anop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
int ilen = gbOpLength(gb_op[data[0]].type);
if(ilen>len)
ilen=0;
memset (op, '\0', sizeof (RAnalOp));
op->addr = addr;
op->type = R_ANAL_OP_TYPE_UNK;
switch (data[0])
{
case 0x00:
case 0x10:
op->type = R_ANAL_OP_TYPE_NOP;
break;
case 0x01:
case 0x06:
case 0x0e:
case 0x11:
case 0x16:
case 0x1e:
case 0x21:
case 0x26:
case 0x2e:
case 0x31:
case 0x36:
case 0x3e:
case 0xf8:
case 0xf9:
op->type = R_ANAL_OP_TYPE_MOV; // LD
break;
case 0x03:
case 0x04:
case 0x0c:
case 0x13:
case 0x14:
case 0x1c:
case 0x23:
case 0x24:
case 0x2c:
case 0x33:
case 0x34:
case 0x3c:
op->type = R_ANAL_OP_TYPE_ADD; // INC
break;
case 0x02:
case 0x08:
case 0x12:
case 0x22:
case 0x32:
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x47:
case 0x48:
case 0x49:
case 0x4a:
case 0x4b:
case 0x4c:
case 0x4d:
case 0x4f:
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
case 0x57:
case 0x58:
case 0x59:
case 0x5a:
case 0x5b:
case 0x5c:
case 0x5d:
case 0x5f:
case 0x60:
case 0x61:
case 0x62:
case 0x63:
case 0x64:
case 0x65:
case 0x67:
case 0x68:
case 0x69:
case 0x6a:
case 0x6b:
case 0x6c:
case 0x6d:
case 0x6f:
case 0x70:
case 0x71:
case 0x72:
case 0x73:
case 0x74:
case 0x75:
case 0x77:
case 0xe2:
case 0xea:
op->type = R_ANAL_OP_TYPE_STORE; //LD
break;
case 0xe0:
meta_gb_hardware_cmt(anal->meta, data[1], addr);
op->type = R_ANAL_OP_TYPE_STORE;
break;
case 0x78:
case 0x79:
case 0x7a:
case 0x7b:
case 0x7c:
case 0x7d:
case 0x7e:
case 0x7f:
op->type = R_ANAL_OP_TYPE_MOV; // LD
break;
case 0x0a:
case 0x1a:
case 0x2a:
case 0x3a:
case 0x46:
case 0x4e:
case 0x56:
case 0x5e:
case 0x66:
case 0x6e:
case 0xf2:
case 0xfa:
op->type = R_ANAL_OP_TYPE_LOAD;
break;
case 0xf0:
meta_gb_hardware_cmt(anal->meta, data[1], addr);
op->type = R_ANAL_OP_TYPE_LOAD;
break;
case 0x09:
case 0x19:
case 0x29:
case 0x39:
case 0x80:
case 0x81:
case 0x82:
case 0x83:
case 0x84:
case 0x85:
case 0x86:
case 0x87:
case 0xc6:
op->type = R_ANAL_OP_TYPE_ADD;
break;
case 0x88:
case 0x89:
case 0x8a:
case 0x8b:
case 0x8c:
case 0x8d:
case 0x8f:
op->type = R_ANAL_OP_TYPE_ADD; // ADC
break;
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97:
case 0xd6:
op->type = R_ANAL_OP_TYPE_SUB;
break;
case 0x98:
case 0x99:
case 0x9a:
case 0x9b:
case 0x9c:
case 0x9d:
case 0x9e:
case 0x9f:
case 0xde:
op->type = R_ANAL_OP_TYPE_SUB; // SBC
break;
case 0xa0:
case 0xa1:
case 0xa2:
case 0xa3:
case 0xa4:
case 0xa5:
case 0xa6:
case 0xa7:
case 0xe6:
op->type = R_ANAL_OP_TYPE_AND;
break;
case 0x07:
case 0x17:
op->type = R_ANAL_OP_TYPE_ROL;
break;
case 0x0f:
case 0x1f:
op->type = R_ANAL_OP_TYPE_ROR;
break;
case 0x2f: //cpl
case 0xa8:
case 0xa9:
case 0xaa:
case 0xab:
case 0xac:
case 0xad:
case 0xae:
case 0xaf:
case 0xee:
op->type = R_ANAL_OP_TYPE_XOR;
break;
case 0xb0:
case 0xb1:
case 0xb2:
case 0xb3:
case 0xb4:
case 0xb5:
case 0xb6:
case 0xb7:
case 0xf6:
op->type = R_ANAL_OP_TYPE_OR;
break;
case 0xb8:
case 0xb9:
case 0xba:
case 0xbb:
case 0xbc:
case 0xbd:
case 0xbe:
case 0xbf:
case 0xfe:
op->type = R_ANAL_OP_TYPE_CMP;
break;
case 0xc0:
case 0xc8:
case 0xd0:
case 0xd8:
op->eob = 1;
op->type = R_ANAL_OP_TYPE_CRET;
break;
case 0xc9:
case 0xd9:
op->eob = 1;
op->type = R_ANAL_OP_TYPE_RET;
break;
case 0x05:
case 0x0b:
case 0x0d:
case 0x15:
case 0x1b:
case 0x1d:
case 0x25:
case 0x2b:
case 0x2d:
case 0x35:
case 0x3b:
case 0x3d:
op->type = R_ANAL_OP_TYPE_SUB; // DEC
break;
case 0xc5:
case 0xd5:
case 0xe5:
case 0xf5:
op->type = R_ANAL_OP_TYPE_PUSH;
break;
case 0xc1:
case 0xd1:
case 0xe1:
case 0xf1:
op->type = R_ANAL_OP_TYPE_POP;
break;
case 0xc3:
op->jump = (data[2]*0x100)+data[1];
op->fail = addr+ilen;
op->type = R_ANAL_OP_TYPE_JMP;
op->eob = 1;
break;
case 0x18: // JR
op->jump = addr+data[1]-0x80; //is this wrong?
op->fail = addr+ilen;
op->type = R_ANAL_OP_TYPE_JMP;
break;
case 0x20:
case 0x28:
case 0x30:
case 0x38: //JR cond
op->jump = addr+data[1]-0x80; //is this wrong?
op->fail = addr+ilen;
op->type = R_ANAL_OP_TYPE_CJMP;
break;
case 0xc2:
case 0xca:
case 0xd2:
case 0xda:
op->jump = (data[2]*0x100)+data[1];
op->fail = addr+ilen;
op->type = R_ANAL_OP_TYPE_JMP;
op->eob=1;
break;
case 0xe9:
case 0x76: /*
DAH-FUCK: halts must be handled as jumps:
http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf (page 20)
*/
op->type = R_ANAL_OP_TYPE_UJMP;
break;
case 0xc4:
case 0xcc:
case 0xcd:
case 0xd4:
case 0xdc:
op->jump = (data[2]*0x100)+data[1];
op->fail = addr+3;
op->type = R_ANAL_OP_TYPE_CALL;
op->eob = 1;
break;
case 0xc7:
case 0xcf:
case 0xd7:
case 0xdf:
case 0xe7:
case 0xef:
case 0xf7:
case 0xff:
op->type = R_ANAL_OP_TYPE_TRAP;
op->eob = 1;
break; // RST
case 0xd3:
case 0xdb:
case 0xdd:
case 0xe3:
case 0xe4:
case 0xeb:
case 0xec:
case 0xed:
case 0xfc:
case 0xfd:
op->type = R_ANAL_OP_TYPE_ILL;
break;
case 0xcb:
switch(data[1]/8)
{
case 0:
case 2:
case 4:
case 6: //swap
op->type = R_ANAL_OP_TYPE_ROL;
break;
case 1:
case 3:
case 5:
case 7:
op->type = R_ANAL_OP_TYPE_ROR;
break;
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
op->type = R_ANAL_OP_TYPE_AND;
break; //bit
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
op->type = R_ANAL_OP_TYPE_XOR;
break; //set
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
op->type = R_ANAL_OP_TYPE_MOV;
break; //res
}
break;
}
op->size = ilen;
return op->size;
}
struct r_anal_plugin_t r_anal_plugin_gb = {
.name = "gb",
.desc = "Gameboy CPU code analysis plugin",
.license = "LGPL3",
.arch = R_SYS_ARCH_Z80,
.bits = 16,
.init = NULL,
.fini = NULL,
.op = &gb_anop,
.set_reg_profile = NULL, //TODO
.fingerprint_bb = NULL,
.fingerprint_fcn = NULL,
.diff_bb = NULL,
.diff_fcn = NULL,
.diff_eval = NULL
};
#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
.type = R_LIB_TYPE_ANAL,
.data = &r_anal_plugin_gb
};
#endif

12
libr/anal/p/gb.mk Normal file
View File

@ -0,0 +1,12 @@
OBJ_GB=anal_gb.o
STATIC_OBJ+=${OBJ_GB}
TARGET_GB=anal_gb.${EXT_SO}
ALL_TARGETS+=${TARGET_GB}
#LDFLAGS+=-L../../lib -lr_lib
#LDFLAGS+=-L../../syscall -lr_syscall
#LDFLAGS+=-L../../diff -lr_diff
${TARGET_GB}: ${OBJ_GB}
${CC} $(call libname,anal_gb) ${LDFLAGS} ${CFLAGS} -o anal_gb.${EXT_SO} ${OBJ_GB}

View File

@ -945,6 +945,7 @@ extern RAnalPlugin r_anal_plugin_i8080;
extern RAnalPlugin r_anal_plugin_8051;
extern RAnalPlugin r_anal_plugin_arc;
extern RAnalPlugin r_anal_plugin_ebc;
extern RAnalPlugin r_anal_plugin_gb;
#ifdef __cplusplus
}

View File

@ -52,6 +52,7 @@ anal.m68k
anal.ppc
anal.sparc
anal.ebc
anal.gb
bin.any
bin.bios
bin.bf