jvmreg.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 478 行
C
478 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include "jvm.h"
#include "jvmtypes.h"
#include "madregs.h"
#define BIT_OFF( who ) (offsetof( mad_registers, jvm.who ) * BITS_PER_BYTE)
enum {
RS_NONE,
RS_NUM,
};
#define REG_NAME( name ) const char NAME_##name[] = #name
/* to avoid relocations to R/W data segments */
#define regpick( name, type, s ) REG_NAME( name );
#include "jvmregs.h"
#undef regpick
#define regpick( name, type, reg_set ) \
{ { NAME_##name, \
JVMT_##type, \
BIT_OFF( name ), \
32, \
RS_NONE }, \
},
const jvm_reg_info RegList[] = {
#include "jvmregs.h"
};
static const mad_toggle_strings CPUToggleList[] =
{
{MSTR_MHEX,MSTR_HEX,MSTR_DECIMAL},
{MSTR_NIL,MSTR_NIL,MSTR_NIL}
};
struct mad_reg_set_data {
mad_status (*get_piece)( unsigned piece, char **descript, unsigned *max_descript, const mad_reg_info **reg, mad_type_handle *disp_type, unsigned *max_value );
const mad_toggle_strings *togglelist;
mad_string name;
};
static mad_status CPUGetPiece( unsigned piece,
char **descript,
unsigned *max_descript,
const mad_reg_info **reg,
mad_type_handle *disp_type,
unsigned *max_value );
static const mad_reg_set_data RegSet[] = {
{ CPUGetPiece, CPUToggleList, MSTR_CPU },
};
/*
Return the size of the structure required to hold a register set.
*/
unsigned DIGENTRY MIRegistersSize( void )
{
return( sizeof( struct jvm_mad_registers ) );
}
/*
Perform any conversions on the register set after it's been
received from the trap file. Return MS_OK if nothing was actually
modified, MS_MODIFIED if some changes were made.
*/
mad_status DIGENTRY MIRegistersHost( mad_registers *mr )
{
return( MS_OK );
}
/*
Perform any conversions on the register set required before sending
it to the trap file (undo the effects of a MIRegistersHost). Return
MS_OK if nothing was actually changed, MS_MODIFIED otherwise.
*/
mad_status DIGENTRY MIRegistersTarget( mad_registers *mr )
{
return( MS_OK );
}
/*
Call back to the client routine with pointers to the various
reg set structure(s).
*/
walk_result DIGENTRY MIRegSetWalk( mad_type_kind tk, MI_REG_SET_WALKER *wk, void *d )
{
walk_result wr;
if( tk & MTK_INTEGER ) {
wr = wk( &RegSet[CPU_REG_SET], d );
if( wr != WR_CONTINUE ) return( wr );
}
return( WR_CONTINUE );
}
/*
Return the name of the register set.
*/
mad_string DIGENTRY MIRegSetName( const mad_reg_set_data *rsd )
{
return( rsd->name );
}
/*
Return the register set level string (8086, 186, 286, etc).
*/
unsigned DIGENTRY MIRegSetLevel( const mad_reg_set_data *rsd, unsigned max, char *buff )
{
if( max > 0 ) *buff = '\0';
return( 0 );
}
/*
Return the register set display grouping. A register set is either
displayed as a stream of values that the client displays however it
wishes (return value 0), or as an n X m grid where 'n' is the number
of rows and 'm' is the number of columns. The grouping is the number
of columns (return value m).
*/
unsigned DIGENTRY MIRegSetDisplayGrouping( const mad_reg_set_data *rsd )
{
return( 0 );
}
static mad_status CPUGetPiece( unsigned piece,
char **descript,
unsigned *max_descript,
const mad_reg_info **reg,
mad_type_handle *disp_type,
unsigned *max_value )
{
if( piece >= sizeof( RegList ) / sizeof( RegList[0] ) ) return( MS_FAIL );
*descript = (char *)RegList[piece].info.name;
*max_descript = strlen( *descript );
*disp_type = RegList[piece].info.type;
*max_value = 0;
*reg = &RegList[piece].info;
return( MS_OK );
}
/*
Fill in the information to display one register.
*/
mad_status DIGENTRY MIRegSetDisplayGetPiece( const mad_reg_set_data *rsd,
const mad_registers *mr,
unsigned piece,
char **descript,
unsigned *max_descript,
const mad_reg_info **reg,
mad_type_handle *disp_type,
unsigned *max_value )
{
return( rsd->get_piece( piece, descript, max_descript, reg,
disp_type, max_value ) );
}
static const mad_modify_list DWordReg = { NULL, JVMT_N32_PTR, MSTR_NIL };
/*
A particular register has been selected for modification. Indicate
what are the legal ranges of values for it.
*/
mad_status DIGENTRY MIRegSetDisplayModify( const mad_reg_set_data *rsd, const mad_reg_info *ri, const mad_modify_list **possible_p, unsigned *num_possible_p )
{
*num_possible_p = 1;
*possible_p = &DWordReg;
return( MS_OK );
}
/*
Query whether a register value differs between the two register
sets 'old' and 'cur'. The following return codes are possible:
MS_OK - value is unchanged
MS_MODIFIED - value is different
MS_MODIFIED_SIGNIFICANTLY - value has changed
in a way that the user
cares about
*/
mad_status DIGENTRY MIRegModified( const mad_reg_set_data *rsd, const mad_reg_info *ri, const mad_registers *old, const mad_registers *cur )
{
addr_ptr new_ip;
unsigned_8 *p_old;
unsigned_8 *p_cur;
unsigned mask;
unsigned size;
if( ri->bit_start == BIT_OFF( pc ) ) {
new_ip = old->jvm.pc;
//NYI: find length of instruction
new_ip.offset += sizeof( unsigned_32 );
if( new_ip.segment != cur->jvm.pc.segment ||
new_ip.offset != cur->jvm.pc.offset ) {
return( MS_MODIFIED_SIGNIFICANTLY );
} else if( old->jvm.pc.segment != cur->jvm.pc.segment ||
old->jvm.pc.offset != cur->jvm.pc.offset ) {
return( MS_MODIFIED );
}
} else {
p_old = (unsigned_8 *)old + (ri->bit_start / BITS_PER_BYTE);
p_cur = (unsigned_8 *)cur + (ri->bit_start / BITS_PER_BYTE);
size = ri->bit_size;
if( size >= BITS_PER_BYTE ) {
/* it's going to be byte aligned */
return( memcmp( p_old, p_cur, size / BITS_PER_BYTE ) != 0 ? MS_MODIFIED_SIGNIFICANTLY : MS_OK );
} else {
mask = (1 << size) - 1;
#define GET_VAL( w ) (((*p_##w >> (ri->bit_start % BITS_PER_BYTE))) & mask)
return( GET_VAL( old ) != GET_VAL( cur ) ? MS_MODIFIED_SIGNIFICANTLY : MS_OK );
}
}
return( MS_OK );
}
/*
Given a register, fill in 'a' with the address that the register
points at.
*/
mad_status DIGENTRY MIRegInspectAddr( const mad_reg_info *ri, const mad_registers *mr, address *a )
{
unsigned bit_start;
unsigned_32 *p;
memset( a, 0, sizeof( *a ) );
bit_start = ri->bit_start;
p = (unsigned_32 *)((unsigned_8 *)mr + (bit_start / BITS_PER_BYTE));
a->mach.offset = *p;
return( MS_OK );
}
/*
Return the toggle list strings for the register set.
*/
const mad_toggle_strings *DIGENTRY MIRegSetDisplayToggleList( const mad_reg_set_data *rsd )
{
return( rsd->togglelist );
}
/*
Get/Set the register set toggle bits. For a particular bit, the
following algorithm is used:
on off result
-- --- ------
0 0 bit left unchanged
1 0 bit set to 1
0 1 bit set to 0
1 1 bit toggled from previous value
(it operates the same as a JK flip-flop).
Return the new toggle state.
*/
unsigned DIGENTRY MIRegSetDisplayToggle( const mad_reg_set_data *rsd, unsigned on, unsigned off )
{
unsigned toggle;
unsigned *bits;
unsigned index;
unsigned old;
toggle = on & off;
index = rsd - &RegSet[CPU_REG_SET];
bits = &MADState->reg_state[index];
old = *bits;
*bits ^= toggle;
*bits |= on & ~toggle;
*bits &= ~off | toggle;
return( *bits );
}
/*
Walk a register set/register, calling back the client with
mad_reg_info structures for all the registers contained in the
register set/register.
If 'ri' is non-NULL, walk all the sub registers of the
indicated register, otherwise walk all the registers of
the register set 'rsd'.
*/
walk_result DIGENTRY MIRegWalk( const mad_reg_set_data *rsd, const mad_reg_info *ri, MI_REG_WALKER *wk, void *d )
{
walk_result wr;
if( ri == NULL ) {
wr = wk( &RegList[CPU_REG_SET].info, 0, d );
if( wr != WR_CONTINUE ) return( wr );
}
return( WR_CONTINUE );
}
/*
Get the address pointed at by the following special registers:
MSR_IP - instruction pointer
MSR_SP - stack pointer
MSR_FP - frame pointer
*/
void DIGENTRY MIRegSpecialGet( mad_special_reg sr, const mad_registers *mr, addr_ptr *ma )
{
ma->segment = 0;
switch( sr ) {
case MSR_IP:
ma->offset = mr->jvm.pc.offset;
ma->segment = mr->jvm.pc.segment;
break;
case MSR_SP:
ma->offset = mr->jvm.optop;
break;
case MSR_FP:
ma->offset = mr->jvm.frame.offset;
break;
}
}
/*
Set a special register to the address 'a'.
*/
void DIGENTRY MIRegSpecialSet( mad_special_reg sr, mad_registers *mr, const addr_ptr *ma )
{
switch( sr ) {
case MSR_IP:
mr->jvm.pc.offset = ma->offset;
mr->jvm.pc.segment = ma->segment;
break;
case MSR_SP:
mr->jvm.optop = ma->offset;
break;
case MSR_FP:
mr->jvm.frame.offset = ma->offset;
break;
}
}
/*
Get the name of a special register.
*/
unsigned DIGENTRY MIRegSpecialName( mad_special_reg sr, const mad_registers *mr, mad_address_format af, unsigned max, char *buff )
{
unsigned idx;
unsigned len;
const char *p;
switch( sr ) {
case MSR_IP:
idx = IDX_pc;
break;
case MSR_SP:
idx = IDX_optop;
break;
case MSR_FP:
idx = IDX_frame;
break;
}
p = RegList[idx].info.name;
len = strlen( p );
if( max > 0 ) {
--max;
if( max > len ) max = len;
memcpy( buff, p, max );
buff[max] = '\0';
}
return( len );
}
/*
Convert a DIP context item enumeration to a MAD mad_reg_info
pointer.
*/
const mad_reg_info *DIGENTRY MIRegFromContextItem( context_item ci )
{
const mad_reg_info *reg;
reg = NULL;
switch( ci ) {
case CI_JVM_pc:
reg = &RegList[IDX_pc].info;
break;
case CI_JVM_optop:
reg = &RegList[IDX_optop].info;
break;
case CI_JVM_frame:
reg = &RegList[IDX_frame].info;
break;
case CI_JVM_vars:
reg = &RegList[IDX_vars].info;
break;
}
return( reg );
}
/*
The client is about to modify a register (or registers).
*/
void DIGENTRY MIRegUpdateStart( mad_registers *mr, unsigned flags, unsigned bit_start, unsigned bit_size )
{
}
/*
The client has just finished modifying a register (or registers).
The MAD should take this chance to notify the client on what displays
need to be updated. MCNotify should be called for the following
MNT_MODIFY_REG - to notify client which register set has
changed (2d parm is register set pointer).
MNT_MODIFY_IP - instruction pointer special reg has changed.
MNT_MODIFY_SP - stack pointer special reg has changed.
MNT_MODIFY_FP - frame pointer special reg has changed.
*/
void DIGENTRY MIRegUpdateEnd( mad_registers *mr, unsigned flags, unsigned bit_start, unsigned bit_size )
{
unsigned bit_end;
bit_end = bit_start + bit_size;
MCNotify( MNT_MODIFY_REG, (void *)&RegSet[CPU_REG_SET] );
switch( bit_start ) {
case BIT_OFF( pc ):
MCNotify( MNT_MODIFY_IP, NULL );
break;
case BIT_OFF( optop ):
MCNotify( MNT_MODIFY_SP, NULL );
break;
case BIT_OFF( frame ):
MCNotify( MNT_MODIFY_FP, NULL );
break;
}
}
mad_status RegInit()
{
return( MS_OK );
}
void RegFini()
{
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?