Files
sigmaker-ida/idasdk76/module/hppa/hppa_cfh.cpp
2021-10-31 21:20:46 +02:00

249 lines
7.7 KiB
C++

/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
// This file contains custom fixup handlers for simplified fixups with high
// and low parts. The word "simplified" means that we don't use LR and RR
// rounding modes as prescribed in the documentation. We replace them by "
// and R rounding modes.
// They are used for the relocations:
// - R_PARISC_DIR21L, R_PARISC_DPREL21L
// - R_PARISC_DIR14R, R_PARISC_DPREL14R
#include <fixup.hpp>
//--------------------------------------------------------------------------
static uval_t idaapi l21_get_value(const fixup_handler_t * /*fh*/, ea_t ea)
{
uint32 insn = get_dword(ea);
// extract `im21' from "Long immediate" instruction
return as21(insn);
}
//----------------------------------------------------------------------------
static bool idaapi l21_patch_value(
const fixup_handler_t * /*fh*/,
ea_t ea,
const fixup_data_t &fd)
{
uint32 insn = get_dword(ea);
ea_t expr = fd.off + fd.displacement;
// 33222222222211111111110000000000
// 10987654321098765432109876543210
// abbbbbbbbbbbccdddddee___________ expr
// ___________dddddcceebbbbbbbbbbba insn
// 10987654321098765432109876543210
uint32 im21 = (((expr >> 31) & 0x001) << 0) // a
| (((expr >> 20) & 0x7FF) << 1) // b
| (((expr >> 18) & 0x003) << 14) // c
| (((expr >> 13) & 0x01F) << 16) // d
| (((expr >> 11) & 0x003) << 12); // e
put_dword(ea, (insn & 0xFFE00000) | im21);
return true;
}
//--------------------------------------------------------------------------
static bool idaapi l21_calc_reference_data(
ea_t *target,
ea_t *base,
ea_t /*from*/,
const refinfo_t &ri,
adiff_t opval)
{
if ( ri.target == BADADDR
|| ri.base == BADADDR
|| ri.is_subtract() )
{
return false;
}
ea_t fullvalue = ri.target + ri.tdelta - ri.base;
uint32 calc_opval = fullvalue & 0xFFFFF800;
if ( calc_opval != uint32(opval) )
return false;
*target = ri.target;
*base = ri.base;
return true;
}
//--------------------------------------------------------------------------
static void idaapi l21_get_format(qstring *format)
{
*format = COLSTR("l%%%s", SCOLOR_KEYWORD);
}
//--------------------------------------------------------------------------
static const custom_refinfo_handler_t ref_l21 =
{
sizeof(custom_refinfo_handler_t),
"L21",
"right-justified, high-order 21 bits",
0, // properties (currently 0)
NULL, // gen_expr
l21_calc_reference_data, // calc_reference_data
l21_get_format, // get_format
};
//--------------------------------------------------------------------------
// we use the R rounding mode (11-bit) in this fixup
// but here we return the full immediated value (14-bit or 16-bit)
static uval_t idaapi r11_get_value(const fixup_handler_t * /*fh*/, ea_t ea)
{
hppa_t &pm = *GET_MODULE_DATA(hppa_t);
uint32 insn = get_dword(ea);
// extract `im14' from "Load/Store" instruction
return sval_t(int16(pm.get_ldo(insn)));
}
//----------------------------------------------------------------------------
static bool idaapi r11_patch_value(
const fixup_handler_t * /*fh*/,
ea_t ea,
const fixup_data_t &fd)
{
hppa_t &pm = *GET_MODULE_DATA(hppa_t);
uint32 insn = get_dword(ea);
// we use the R rounding mode (11-bit) in this fixup
ea_t expr = (fd.off + fd.displacement) & 0x7FF;
if ( pm.psw_w() )
{
// 33222222222211111111110000000000
// 10987654321098765432109876543210
// ________________abbccccccccccccc expr
// ________________BBccccccccccccca insn
// 10987654321098765432109876543210
// B = a == 0 ? b : ~b;
uint32 a = (expr >> 15) & 0x0001;
uint32 b = (expr >> 13) & 0x0003;
if ( a != 0 ) //-V547 'a != 0' is always false
b = ~b;
uint32 c = expr & 0x1FFF;
uint32 im16 = a | (b << 14) | (c << 1);
put_dword(ea, (insn & 0xFFFF0000) | im16);
}
else
{
// 33222222222211111111110000000000
// 10987654321098765432109876543210
// __________________abbbbbbbbbbbbb expr
// __________________bbbbbbbbbbbbba insn
// 10987654321098765432109876543210
uint32 im14 = (((expr >> 13) & 0x0001) << 0) // a
| ((expr & 0x1FFF) << 1); // b
put_dword(ea, (insn & 0xFFFFC000) | im14);
}
return true;
}
//--------------------------------------------------------------------------
static bool idaapi r11_calc_reference_data(
ea_t *target,
ea_t *base,
ea_t /*from*/,
const refinfo_t &ri,
adiff_t opval)
{
if ( ri.target == BADADDR
|| ri.base == BADADDR
|| ri.is_subtract() )
{
return false;
}
ea_t fullvalue = ri.target + ri.tdelta - ri.base;
uint32 calc_opval = fullvalue & 0x7FF;
if ( calc_opval != uint32(opval) )
return false;
*target = ri.target;
*base = ri.base;
return true;
}
//--------------------------------------------------------------------------
static void idaapi r11_get_format(qstring *format)
{
*format = COLSTR("r%%%s", SCOLOR_KEYWORD);
}
//--------------------------------------------------------------------------
static const custom_refinfo_handler_t ref_r11 =
{
sizeof(custom_refinfo_handler_t),
"R11",
"low-order 11 bits",
0, // properties (currently 0)
NULL, // gen_expr
r11_calc_reference_data, // calc_reference_data
r11_get_format, // get_format
};
//--------------------------------------------------------------------------
struct hppa_cf_t
{
fixup_handler_t cfh_l21 =
{
sizeof(fixup_handler_t),
"L21", // name
FHF_CODE // verify that fixup points to code
| FHF_FORCE_CODE, // convert unknonw item to code
4, 0, 0, 0, // size, width, shift
REFINFO_CUSTOM, // reftype
NULL, // apply
l21_get_value, // get_value
l21_patch_value, // patch_value
};
fixup_handler_t cfh_r11 =
{
sizeof(fixup_handler_t),
"R11", // name
FHF_CODE // verify that fixup points to code
| FHF_FORCE_CODE, // convert unknonw item to code
4, 0, 0, 0, // size, width, shift
REFINFO_CUSTOM, // reftype
NULL, // apply
r11_get_value, // get_value
r11_patch_value, // patch_value
};
fixup_type_t cfh_l21_id = 0; // ids of fixup handlers
fixup_type_t cfh_r11_id = 0;
int ref_l21_id = 0; // ids of refinfo handlers
int ref_r11_id = 0;
};
//--------------------------------------------------------------------------
void hppa_t::init_custom_refs()
{
if ( hppa_cf == nullptr )
{
hppa_cf = new hppa_cf_t;
hppa_cf->cfh_l21_id = register_custom_fixup(&hppa_cf->cfh_l21);
hppa_cf->cfh_r11_id = register_custom_fixup(&hppa_cf->cfh_r11);
hppa_cf->ref_l21_id = register_custom_refinfo(&ref_l21);
hppa_cf->ref_r11_id = register_custom_refinfo(&ref_r11);
hppa_cf->cfh_l21.reftype = REFINFO_CUSTOM | hppa_cf->ref_l21_id;
hppa_cf->cfh_r11.reftype = REFINFO_CUSTOM | hppa_cf->ref_r11_id;
}
}
//--------------------------------------------------------------------------
void hppa_t::term_custom_refs()
{
if ( hppa_cf != nullptr )
{
hppa_cf->cfh_l21.reftype = REFINFO_CUSTOM;
hppa_cf->cfh_r11.reftype = REFINFO_CUSTOM;
unregister_custom_refinfo(hppa_cf->ref_r11_id);
unregister_custom_refinfo(hppa_cf->ref_l21_id);
unregister_custom_fixup(hppa_cf->cfh_r11_id);
unregister_custom_fixup(hppa_cf->cfh_l21_id);
delete hppa_cf;
hppa_cf = nullptr;
}
}