mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1834 lines
52 KiB
1834 lines
52 KiB
|
|
/* */
|
|
/* disasm */
|
|
/* disassembler for CodeView */
|
|
/* */
|
|
/***************************************************************************/
|
|
/* */
|
|
/* @ Purpose: To disassemble one 80x86 instruction at address loc and */
|
|
/* return the resulting string in dst. */
|
|
/* */
|
|
/* @ Functions included: */
|
|
/* */
|
|
/* void DIdisasm(ADDR *loc,int option,char *dst, stuct ea *ea) */
|
|
/* */
|
|
/* */
|
|
/* Revision History: */
|
|
/* */
|
|
/* */
|
|
/***************************************************************************/
|
|
|
|
#include "d3.h"
|
|
|
|
/***** macros and defines *****/
|
|
|
|
|
|
#define BIT20(b) (b & 0x07)
|
|
#define BIT53(b) (b >> 3 & 0x07)
|
|
#define BIT76(b) (b >> 6 & 0x03)
|
|
#define MAXL 20
|
|
#define MAXOPLEN 10
|
|
|
|
#define OBOFFSET 26
|
|
#define OBOPERAND 34
|
|
#define OBLINEEND 79
|
|
|
|
#define iregNone (-1)
|
|
|
|
/***** static tables and variables *****/
|
|
|
|
|
|
static int rgbOverride[] = {0x3e, 0x36, 0x2e, 0x26};
|
|
static char lregtab[] = "alcldlblahchdhbhaxcxdxbxspbpsidi"; /* reg table */
|
|
static char uregtab[] = "ALCLDLBLAHCHDHBHAXCXDXBXSPBPSIDI";
|
|
static char *regtab = &uregtab[0];
|
|
|
|
static PCH mrmtb16[] = { "bx+si", /* modRM string table (16-bit) */
|
|
"bx+di",
|
|
"bp+si",
|
|
"bp+di",
|
|
"si",
|
|
"di",
|
|
"bp",
|
|
"bx"
|
|
};
|
|
|
|
static PCH mrmtb32[] = { "eax", /* modRM string table (32-bit) */
|
|
"ecx",
|
|
"edx",
|
|
"ebx",
|
|
"esp",
|
|
"ebp",
|
|
"esi",
|
|
"edi"
|
|
};
|
|
|
|
static char seg16[8] = { CV_REG_DS, CV_REG_DS, CV_REG_SS, CV_REG_SS,
|
|
CV_REG_DS, CV_REG_DS, CV_REG_SS, CV_REG_DS };
|
|
static char reg16[8] = { CV_REG_BX, CV_REG_BX, CV_REG_BP, CV_REG_BP,
|
|
CV_REG_SI, CV_REG_DI, CV_REG_BP, CV_REG_BX };
|
|
static char reg16_2[4] = { CV_REG_SI, CV_REG_DI, CV_REG_SI, CV_REG_DI };
|
|
|
|
static char seg32[8] = { CV_REG_DS, CV_REG_DS, CV_REG_DS, CV_REG_DS,
|
|
CV_REG_SS, CV_REG_SS, CV_REG_DS, CV_REG_DS };
|
|
static char reg32[8] = { CV_REG_EAX, CV_REG_ECX, CV_REG_EDX, CV_REG_EBX,
|
|
CV_REG_ESP, CV_REG_EBP, CV_REG_ESI, CV_REG_EDI };
|
|
|
|
|
|
static char lsregtab[] = "ecsdfg"; // first letter of ES, CS, SS, DS, FS, GS
|
|
static char usregtab[] = "ECSDFG";
|
|
static char *sregtab = &usregtab[0];
|
|
|
|
|
|
char lhexdigit[] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
|
char uhexdigit[] = { '0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
|
|
|
char *hexdigit = &uhexdigit[0];
|
|
|
|
static int fUpper = TRUE;
|
|
|
|
static int mod = 0; /* mod of mod/rm byte */
|
|
static int rm = 0; /* rm of mod/rm byte */
|
|
static int ttt = 0; /* return reg value (of mod/rm) */
|
|
static unsigned char FAR*pMem = (unsigned char *)NULL; /* current position in instruction */
|
|
static int mode_32 = '\0'; /* local addressing mode indicator */
|
|
static int opsize_32 = 0; /* operand size flag */
|
|
|
|
static char RgchSegOvr[ 8 ];
|
|
static PCH PchSegOvr = NULL; // segment override indicator
|
|
static char segOvrIndx; // Index of overriden segment
|
|
static int EAsize [2] = {0}; // size of effective address item
|
|
static long EAaddr [2] = {0}; // offset of effective address
|
|
static PCH pchEAseg[2] = {0}; // normal segment for operand
|
|
static char EAseg [2] = "\0";
|
|
static BOOL FDwordTable;
|
|
|
|
// internal function definitions
|
|
|
|
typedef LPCH FAR *LPLPCH;
|
|
|
|
#ifdef D3DM
|
|
typedef enum {
|
|
osoNone = 0,
|
|
osoSymbols = 1,
|
|
osoSegment = 2
|
|
} OSO;
|
|
#endif
|
|
|
|
|
|
void DIdoModrm(HPID,HTID,BOOL,LPADDR,DOP,LPLPCH, int * );
|
|
int DumpEA ( HPID, HTID, BOOL, LPADDR, LPCH, int );
|
|
void CalcMain ( HPID, HTID, BOOL,DOP, LPADDR, LPB, int, int FAR *,
|
|
LPCH, int, LPCH, int, LPCH, int );
|
|
void CalcFPInt ( HPID, HTID, BOOL, DOP, LPADDR, int, LPCH, int );
|
|
|
|
int DumpAddress ( LPADDR, LPCH, int, BOOL );
|
|
int DumpGeneric ( LSZ, LPCH, int );
|
|
int DumpComment ( LSZ, LPCH, int );
|
|
|
|
void OutputAddr(LPLPCH, int *, LPADDR, int, BOOL );
|
|
void OutputHexString(LPLPCH, int *, LPCH, int);
|
|
void OutputHexValue(LPLPCH, int *, LPCH, int, int);
|
|
void OutputHexCode(LPLPCH , LPCH, int);
|
|
void OutputIString ( LPLPCH, int *, LPCH );
|
|
void OutputString(LPLPCH, int *, LPCH);
|
|
void GetSymbol ( ULONG, LPCH, LONG * );
|
|
ULONG GetNextOffset(BOOL);
|
|
|
|
char rgindx[] = {CV_REG_ES,CV_REG_CS,CV_REG_SS,CV_REG_DS};
|
|
#define GETINDX(op) (rgindx[(op-0x26) / 8])
|
|
|
|
|
|
|
|
|
|
//
|
|
// The following functions are module-specific and are defined in a separate
|
|
// file.
|
|
//
|
|
void OutputSymbol ( HPID, HTID, BOOL, BOOL, LPADDR, int, int, LPADDR, LPLPCH, int * );
|
|
XOSD GetRegisterValue( HPID, HTID, UINT, LONG );
|
|
XOSD SetAddress( HPID, HTID, UINT, LONG );
|
|
XOSD ReadMemBuffer( HPID, HTID, UINT, LONG );
|
|
LSZ ObtainSymbol( PADDR, SOP, PADDR, LSZ, LONG* );
|
|
|
|
|
|
|
|
#define CCHMAX 256
|
|
static char rgchDisasm [ CCHMAX ];
|
|
|
|
static HPID hpidLocal;
|
|
static HTID htidLocal;
|
|
|
|
XOSD
|
|
Disassemble(
|
|
HPID hpid,
|
|
HTID htid,
|
|
LPSDI lpsdi,
|
|
PVOID Memory,
|
|
INT MemorySize,
|
|
BOOL FullDisasm
|
|
)
|
|
{
|
|
|
|
XOSD xosd = xosdNone;
|
|
int cchMax = CCHMAX;
|
|
DOP dop = lpsdi->dop;
|
|
LPCH lpchOut = rgchDisasm;
|
|
int ichCur = 0;
|
|
ADDR addrStart = lpsdi->addr;
|
|
int cch = 0;
|
|
int cb;
|
|
int cbUsed=0;
|
|
|
|
BYTE *rgb;
|
|
|
|
char rgchRaw [ MAXL * 2 + 1 ];
|
|
char rgchOpcode [ 20 ];
|
|
char rgchOperands [ 120 ];
|
|
char rgchEA [ 44 ];
|
|
char rgchComment [ 120 ];
|
|
|
|
hpidLocal = hpid;
|
|
htidLocal = htid;
|
|
|
|
FDwordTable = FALSE;
|
|
|
|
_fmemset ( rgchRaw, 0, sizeof ( rgchRaw ) );
|
|
_fmemset ( rgchOpcode, 0, sizeof ( rgchOpcode ) );
|
|
_fmemset ( rgchOperands, 0, sizeof ( rgchOperands ) );
|
|
_fmemset ( rgchComment, 0, sizeof ( rgchComment ) );
|
|
_fmemset ( rgchEA, 0, sizeof ( rgchEA ) );
|
|
|
|
lpsdi->ichAddr = -1;
|
|
lpsdi->ichBytes = -1;
|
|
lpsdi->ichOpcode = -1;
|
|
lpsdi->ichOperands = -1;
|
|
lpsdi->ichComment = -1;
|
|
lpsdi->ichEA0 = -1;
|
|
lpsdi->ichEA1 = -1;
|
|
lpsdi->ichEA2 = -1;
|
|
|
|
lpsdi->cbEA0 = 0;
|
|
lpsdi->cbEA1 = 0;
|
|
lpsdi->cbEA2 = 0;
|
|
|
|
lpsdi->fAssocNext = 0;
|
|
lpsdi->fIsCall = 0;
|
|
lpsdi->fIsBranch = 0;
|
|
lpsdi->fJumpTable = 0;
|
|
|
|
lpsdi->lpch = rgchDisasm;
|
|
|
|
//
|
|
// Set up for upper or lower case
|
|
//
|
|
fUpper = ( dop & dopUpper ) == dopUpper;
|
|
if ( fUpper ) {
|
|
hexdigit = uhexdigit;
|
|
regtab = uregtab;
|
|
sregtab = usregtab;
|
|
} else {
|
|
hexdigit = lhexdigit;
|
|
regtab = lregtab;
|
|
sregtab = lsregtab;
|
|
}
|
|
|
|
mode_32 = opsize_32 = ADDR_IS_OFF32(addrStart);
|
|
|
|
//
|
|
// Output the address if it is requested
|
|
//
|
|
if ( ( dop & dopAddr ) == dopAddr ) {
|
|
cch = DumpAddress ( &addrStart, lpchOut, cchMax, (dop & dopFlatAddr) );
|
|
|
|
lpsdi->ichAddr = 0;
|
|
cchMax -= cch;
|
|
lpchOut += cch;
|
|
ichCur += cch;
|
|
}
|
|
|
|
rgb = (BYTE *)Memory;
|
|
cb = MemorySize;
|
|
|
|
if ( cb <= 0 ) {
|
|
|
|
_fmemcpy ( rgchRaw, " ??", 4 );
|
|
_fmemcpy ( rgchOpcode, "???", 4 );
|
|
offAddr ( lpsdi->addr )++;
|
|
|
|
} else {
|
|
|
|
CalcMain (
|
|
hpid,
|
|
htid,
|
|
FullDisasm,
|
|
lpsdi->dop, &lpsdi->addr, rgb, cb, &cbUsed,
|
|
rgchOpcode, sizeof(rgchOpcode),
|
|
rgchOperands, sizeof(rgchOperands),
|
|
rgchComment, sizeof(rgchComment));
|
|
|
|
if ( offAddr(lpsdi->addr) > 0xFFFFFFFF - cbUsed ) {
|
|
return xosdBadAddress;
|
|
}
|
|
|
|
lpsdi->fJumpTable = FDwordTable;
|
|
|
|
if ( dop & dopRaw ) {
|
|
LPCH lpchT = rgchRaw;
|
|
|
|
OutputHexCode ( &lpchT, rgb, cbUsed );
|
|
|
|
*lpchT = '\0';
|
|
}
|
|
}
|
|
|
|
if ( ( dop & dopRaw ) && ( cchMax > 0 ) ) {
|
|
cch = DumpGeneric ( rgchRaw, lpchOut, cchMax );
|
|
|
|
lpsdi->ichBytes = ichCur;
|
|
cchMax -= cch;
|
|
lpchOut += cch;
|
|
ichCur += cch;
|
|
}
|
|
|
|
|
|
if ( ( dop & dopOpcode ) && ( cchMax > 0 ) ) {
|
|
cch = DumpGeneric ( rgchOpcode, lpchOut, cchMax );
|
|
|
|
lpsdi->ichOpcode = ichCur;
|
|
cchMax -= cch;
|
|
lpchOut += cch;
|
|
ichCur += cch;
|
|
}
|
|
|
|
if ( ( dop & dopOperands ) && ( cchMax > 0 ) && ( rgchOperands [ 0 ] != '\0' ) ) {
|
|
cch = DumpGeneric ( rgchOperands, lpchOut, cchMax );
|
|
|
|
lpsdi->ichOperands = ichCur;
|
|
cchMax -= cch;
|
|
lpchOut += cch;
|
|
ichCur += cch;
|
|
}
|
|
|
|
if ( ( dop & dopOperands ) && ( cchMax > 0 ) && ( rgchComment [ 0 ] != '\0' ) ) {
|
|
cch = DumpComment ( rgchComment, lpchOut, cchMax );
|
|
|
|
lpsdi->ichComment = ichCur;
|
|
cchMax -= cch;
|
|
lpchOut += cch;
|
|
ichCur += cch;
|
|
}
|
|
|
|
if ( dop & dopEA ) {
|
|
cch = DumpEA ( hpid, htid, FullDisasm, &lpsdi->addrEA0, lpchOut, cchMax );
|
|
|
|
if ( cchMax > 0 && cch > 0 ) {
|
|
lpsdi->ichEA0 = ichCur;
|
|
cchMax -= cch;
|
|
lpchOut += cch;
|
|
ichCur += cch;
|
|
}
|
|
}
|
|
|
|
|
|
offAddr ( lpsdi->addr ) += cbUsed;
|
|
|
|
return xosd;
|
|
}
|
|
|
|
|
|
|
|
int
|
|
DumpAddress(
|
|
LPADDR lpaddr,
|
|
LPCH lpch,
|
|
int cchMax,
|
|
BOOL fFlatAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to dump an ADDR packet to a buffer.
|
|
|
|
Arguments:
|
|
|
|
lpaddr - Supplies the address packet to be dumped.
|
|
lpch - Supplies the buffer to format the address in
|
|
cchMax - Supplies the size of the buffer
|
|
fFlatAddr - Supplies TRUE if segments are to be suppressed for 32-bit
|
|
addresses.
|
|
|
|
Return Value:
|
|
|
|
Returns the number of bytes used in the buffer
|
|
|
|
--*/
|
|
{
|
|
LPCH lpchT = lpch;
|
|
ADDR addrT = {0};
|
|
|
|
if (ADDR_IS_FLAT(*lpaddr) == FALSE) {
|
|
fFlatAddr = TRUE;
|
|
} else {
|
|
fFlatAddr = !fFlatAddr;
|
|
}
|
|
|
|
OutputAddr (&lpch, &cchMax, lpaddr,
|
|
(ADDR_IS_OFF32(*lpaddr) + 1) * 2, fFlatAddr );
|
|
*lpch = '\0';
|
|
return lpch - lpchT + 1;
|
|
} /* DumpAddress() */
|
|
|
|
int
|
|
DumpGeneric (
|
|
LSZ lsz,
|
|
LPCH lpch,
|
|
int cchMax
|
|
)
|
|
{
|
|
int cb;
|
|
|
|
cb = strlen(lsz);
|
|
if (cb > cchMax - 1) {
|
|
cb = cchMax - 1;
|
|
}
|
|
|
|
strncpy(lpch, lsz, cb);
|
|
lpch[cb] = 0;
|
|
return cb + 1;
|
|
}
|
|
|
|
int
|
|
DumpComment (
|
|
LSZ lsz,
|
|
LPCH lpch,
|
|
int cchMax
|
|
)
|
|
{
|
|
*(lpch) = ';';
|
|
return DumpGeneric ( lsz, lpch + 1, cchMax - 1 ) + 1;
|
|
}
|
|
|
|
int
|
|
DumpEA (
|
|
HPID hpid,
|
|
HTID htid,
|
|
BOOL FullDisasm,
|
|
LPADDR lpaddr,
|
|
LPCH lpch,
|
|
int cchMax
|
|
)
|
|
{
|
|
LPCH lpchT = lpch;
|
|
int indx;
|
|
int cb;
|
|
BYTE rgb [ MAXL ];
|
|
|
|
for ( indx = 0; indx < 2; indx++ ) {
|
|
|
|
if ( EAsize [ indx ] ) {
|
|
ADDR addr = {0};
|
|
|
|
OutputString ( &lpchT, &cchMax, PchSegOvr ? PchSegOvr : pchEAseg [indx]);
|
|
OutputHexString (&lpchT, &cchMax, (LPB) &EAaddr [ indx ],
|
|
mode_32 ? 4 : 2 );
|
|
|
|
*lpchT++ = '=';
|
|
cchMax -= 1;
|
|
|
|
offAddr ( addr ) = (UOFFSET) EAaddr [ indx ];
|
|
if ( FullDisasm ) {
|
|
|
|
GetRegisterValue( hpid, htid,
|
|
PchSegOvr ? segOvrIndx : EAseg[indx],
|
|
(LONG) (LPW) ( &segAddr ( addr ) ));
|
|
|
|
*lpaddr = addr;
|
|
|
|
SetAddress (hpid, htid, adrCurrent, (LONG) (LPADDR) &addr);
|
|
|
|
cb = ReadMemBuffer( hpid, htid, EAsize [ indx ],
|
|
(LONG) (LPV) rgb);
|
|
|
|
if ( cb == EAsize [ indx ] ) {
|
|
OutputHexString ( &lpchT, &cchMax, rgb, EAsize [ indx ] );
|
|
}
|
|
else {
|
|
if (cchMax < EAsize[indx]) {
|
|
cchMax -= EAsize[indx];
|
|
while ( EAsize [ indx ]-- ) {
|
|
*lpchT++ = '?';
|
|
*lpchT++ = '?';
|
|
}
|
|
}
|
|
}
|
|
*lpchT++ = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
return lpchT - lpch;
|
|
}
|
|
|
|
|
|
void
|
|
CalcMain (
|
|
HPID hpid,
|
|
HTID htid,
|
|
BOOL FullDisasm,
|
|
DOP dop,
|
|
LPADDR lpaddr,
|
|
LPB rgb,
|
|
int cbMax,
|
|
int FAR *lpcbUsed,
|
|
LPCH rgchOpcode,
|
|
int cchOpcode,
|
|
LPCH rgchOperands,
|
|
int cchOperands,
|
|
LPCH rgchComment,
|
|
int cchComment
|
|
)
|
|
{
|
|
int opcode; /* current opcode */
|
|
int opcodeT;
|
|
int olen = 2; /* operand length */
|
|
int alen = 2; /* address length */
|
|
int end = FALSE; /* end of instruction flag */
|
|
int mrm = FALSE; /* indicator that modrm is generated */
|
|
PCH action; /* action for operand interpretation */
|
|
long tmp; /* temporary storage field */
|
|
int indx; /* temporary index */
|
|
int action2; /* secondary action */
|
|
PCH pEAlabel = ""; /* optional label for operand */
|
|
int cbT;
|
|
|
|
int inREP = 0; // needed because we can get into getNxtByte:
|
|
// from *anywhere*, which is in case(REP):
|
|
// (note: this is a very good reason why
|
|
// using 'goto' makes things much harder
|
|
// during maintenance!).
|
|
|
|
char rgchModrm [ 100 ];
|
|
|
|
LPCH lpchOpcode = rgchOpcode;
|
|
LPCH lpchOperands = rgchOperands;
|
|
LPCH lpchModrm = rgchModrm;
|
|
LPCH lpchSegOvr = RgchSegOvr;
|
|
|
|
PchSegOvr = NULL;
|
|
EAsize [ 0 ] = EAsize[1] = 0; /* no effective address */
|
|
pchEAseg [ 0 ] = dszDS_;
|
|
pchEAseg [ 1 ] = dszES_;
|
|
EAseg [ 0 ] = CV_REG_DS;
|
|
EAseg [ 1 ] = CV_REG_ES;
|
|
|
|
olen = alen = (1 + mode_32) << 1; /* set operand/address lengths */
|
|
|
|
pMem = rgb;
|
|
|
|
/*
|
|
* Get an opcode or prefix & output it to the opcode buffer
|
|
*/
|
|
|
|
opcode = *pMem++;
|
|
OutputString ( &lpchOpcode, &cchOpcode, distbl [ opcode ].instruct );
|
|
action = actiontbl + distbl [ opcode ].opr; /* get operand action */
|
|
|
|
/***** loop through all operand actions *****/
|
|
|
|
do {
|
|
|
|
action2 = (*action) & 0xc0;
|
|
|
|
switch ( (*action++) & 0x3f ) {
|
|
|
|
case ALT: /* alter the opcode if 32-bit */
|
|
|
|
if ( opsize_32 ) {
|
|
indx = *action++;
|
|
switch( indx ) {
|
|
case 0:
|
|
/*
|
|
* Map CBW to CWDE
|
|
*/
|
|
|
|
lpchOpcode -= 3;
|
|
cchOpcode += 3;
|
|
OutputString( &lpchOpcode, &cchOpcode, dszCWDE );
|
|
break;
|
|
|
|
case 1:
|
|
/*
|
|
* Map CWD to CDQ
|
|
*/
|
|
|
|
lpchOpcode[-2] = (char) (fUpper ? 'D' : 'd');
|
|
lpchOpcode[-1] = (char) (fUpper ? 'Q' : 'q');
|
|
break;
|
|
|
|
case 2:
|
|
/*
|
|
* Change last letter to 'D' from 'W'
|
|
*/
|
|
|
|
lpchOpcode[-1] = (char) (fUpper ? 'D' : 'd');
|
|
break;
|
|
|
|
case 3:
|
|
/*
|
|
* Append a 'D' to the end of the opcode
|
|
*/
|
|
|
|
OutputString( &lpchOpcode, &cchOpcode, "d");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STROP:
|
|
/*
|
|
* compute size of operands in indx
|
|
* also if dword operands, change fifth
|
|
* opcode letter from 'w' to 'd'.
|
|
*/
|
|
|
|
if ( opcode & 1 ) {
|
|
if ( opsize_32 ) {
|
|
indx = 4;
|
|
*(lpchOpcode - 1) = (char)(fUpper ? 'D' : 'd');
|
|
}
|
|
else {
|
|
indx = 2;
|
|
}
|
|
}
|
|
else {
|
|
indx = 1;
|
|
}
|
|
|
|
if ( *action & 1 ) {
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
CV_REG_SI,
|
|
(LONG) (LPW) &EAaddr[0]
|
|
);
|
|
}
|
|
EAsize[0] = indx;
|
|
|
|
}
|
|
|
|
if ( *action++ & 2 ) {
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
CV_REG_DI,
|
|
(LONG) (LPW) &EAaddr[1]
|
|
);
|
|
}
|
|
EAsize[1] = indx;
|
|
}
|
|
break;
|
|
|
|
case CHR: /* insert a character */
|
|
|
|
*lpchOperands++ = *action++;
|
|
cchOperands -= 1;
|
|
break;
|
|
|
|
case CREG: /* set debug, test or control reg */
|
|
|
|
if ( opcode & 0x04 ) {
|
|
*lpchOperands++ = (char) ( fUpper ? 'T' : 't' );
|
|
}
|
|
else if ( opcode & 0x01 ) {
|
|
*lpchOperands++ = (char) ( fUpper ? 'D' : 'd' );
|
|
}
|
|
else {
|
|
*lpchOperands++ = (char) ( fUpper ? 'C' : 'c' );
|
|
}
|
|
*lpchOperands++ = (char) ( fUpper ? 'R' : 'r' );
|
|
*lpchOperands++ = (char)('0' + ttt);
|
|
cchOperands -= 3;
|
|
break;
|
|
|
|
case SREG2: /* segment register */
|
|
ttt = BIT53(opcode); /* set value to fall through */
|
|
|
|
case SREG3: /* segment register */
|
|
if (ttt > 5) {
|
|
*lpchOperands++ = '?';
|
|
*lpchOperands++ = '?';
|
|
} else {
|
|
*lpchOperands++ = sregtab[ttt]; /* reg is part of modrm */
|
|
*lpchOperands++ = (char) (fUpper ? 'S' : 's');
|
|
}
|
|
cchOperands -= 2;
|
|
break;
|
|
|
|
case BRSTR: /* get index to register string */
|
|
ttt = *action++; /* from action table */
|
|
goto BREGlabel;
|
|
|
|
case BOREG: /* byte register (in opcode) */
|
|
ttt = BIT20(opcode); /* register is part of opcode */
|
|
goto BREGlabel;
|
|
|
|
case ALSTR:
|
|
ttt = 0; /* point to AL register */
|
|
BREGlabel:
|
|
case BREG: /* general register */
|
|
*lpchOperands++ = regtab[ttt * 2];
|
|
*lpchOperands++ = regtab[ttt * 2 + 1];
|
|
cchOperands -= 2;
|
|
break;
|
|
|
|
case WRSTR: /* get index to register string */
|
|
ttt = *action++; /* from action table */
|
|
goto WREGlabel;
|
|
|
|
case VOREG: /* register is part of opcode */
|
|
ttt = BIT20(opcode);
|
|
goto VREGlabel;
|
|
|
|
case AXSTR:
|
|
ttt = 0; /* point to eAX register */
|
|
VREGlabel:
|
|
case VREG: /* general register */
|
|
if (!opsize_32) { /* test for 32bit mode */
|
|
goto WREGlabel;
|
|
}
|
|
case DREG:
|
|
*lpchOperands++ = (char) ( fUpper ? 'E' : 'e' );
|
|
cchOperands -= 1;
|
|
|
|
WREGlabel:
|
|
case WREG: /* register is word size */
|
|
*lpchOperands++ = regtab[ttt * 2 + 16];
|
|
*lpchOperands++ = regtab[ttt * 2 + 17];
|
|
cchOperands -= 2;
|
|
break;
|
|
|
|
case IST_ST:
|
|
OutputString ( &lpchOperands, &cchOperands, "st(0),st" );
|
|
*(lpchOperands - 5) += rm;
|
|
break;
|
|
|
|
case ST_IST:
|
|
OutputString ( &lpchOperands, &cchOperands, "st," );
|
|
case IST:
|
|
OutputString ( &lpchOperands, &cchOperands, "st(0)" );
|
|
*(lpchOperands - 2) += rm;
|
|
break;
|
|
|
|
case BYT: /* set instruction to byte only */
|
|
EAsize[0] = 1;
|
|
pEAlabel = "byte ptr ";
|
|
break;
|
|
|
|
case VAR:
|
|
if (opsize_32)
|
|
goto DWRDlabel;
|
|
|
|
case EWRD:
|
|
opsize_32 = 0;
|
|
|
|
case WRD:
|
|
|
|
EAsize[0] = 2;
|
|
pEAlabel = "word ptr ";
|
|
break;
|
|
|
|
case EDWRD:
|
|
opsize_32 = 1; /* for control reg move, use eRegs */
|
|
case DWRD:
|
|
DWRDlabel:
|
|
EAsize[0] = 4;
|
|
pEAlabel = "dword ptr ";
|
|
break;
|
|
|
|
case FWRD:
|
|
EAsize[0] = 6;
|
|
pEAlabel = "fword ptr ";
|
|
break;
|
|
|
|
case QWRD:
|
|
EAsize[0] = 8;
|
|
pEAlabel = "qword ptr ";
|
|
break;
|
|
|
|
case TBYT:
|
|
EAsize[0] = 10;
|
|
pEAlabel = "tbyte ptr ";
|
|
break;
|
|
|
|
case FARPTR:
|
|
if (opsize_32) {
|
|
EAsize[0] = 6;
|
|
pEAlabel = "fword ptr ";
|
|
}
|
|
else {
|
|
EAsize[0] = 4;
|
|
pEAlabel = "dword ptr ";
|
|
}
|
|
break;
|
|
|
|
case LMODRM: /* output modRM data type */
|
|
if (mod != 3) {
|
|
OutputString ( &lpchOperands, &cchOperands, pEAlabel );
|
|
}
|
|
|
|
case MODRM: /* output modrm string */
|
|
if (mod != 3) {
|
|
if (PchSegOvr) { /* in case of segment override */
|
|
OutputString ( &lpchOperands, &cchOperands, PchSegOvr );
|
|
}
|
|
}
|
|
*lpchModrm = '\0';
|
|
OutputIString ( &lpchOperands, &cchOperands, rgchModrm );
|
|
break;
|
|
|
|
case ADDRP: /* address pointer */
|
|
{
|
|
ADDR addrT = {0};
|
|
|
|
if ( olen == 2 ) {
|
|
ADDRSEG16 ( addrT );
|
|
offAddr ( addrT ) = (UOFFSET) * ( ( unsigned short * ) pMem );
|
|
}
|
|
else {
|
|
ADDRLIN32 ( addrT );
|
|
offAddr ( addrT ) = (UOFFSET) * ( ( unsigned long * ) pMem );
|
|
}
|
|
|
|
segAddr ( addrT ) = * ( (WORD *) ( pMem + olen ) );
|
|
|
|
OutputSymbol (
|
|
hpidLocal,
|
|
htidLocal,
|
|
( (dop & dopSym) ? osoSymbols : osoNone ) | osoSegment,
|
|
FALSE,
|
|
&addrT,
|
|
CV_REG_CS,
|
|
olen,
|
|
lpaddr,
|
|
&lpchOperands,
|
|
&cchOperands
|
|
);
|
|
|
|
pMem += olen + 2;
|
|
}
|
|
break;
|
|
|
|
case REL8: /* relative address 8-bit */
|
|
|
|
if ( opcode == 0xe3 && opsize_32 ) {
|
|
cchOpcode += lpchOpcode - rgchOpcode;
|
|
lpchOpcode = rgchOpcode;
|
|
OutputString ( &lpchOpcode, &cchOpcode, dszJECXZ );
|
|
}
|
|
tmp = (long) *(PCH)pMem++; /* get the 8-bit rel offset */
|
|
goto DoRelDispl;
|
|
|
|
case REL16: /* relative address 16-/32-bit */
|
|
if (opsize_32) {
|
|
tmp = *(long *)pMem; /* get 32-bit relative offset */
|
|
} else {
|
|
tmp = *(USHORT *)pMem; /* get 16-bit relative offset */
|
|
}
|
|
pMem += olen; /* skip over offset */
|
|
|
|
DoRelDispl:
|
|
|
|
tmp += offAddr ( *lpaddr ) + (pMem - rgb); /* calculate address */
|
|
if (!opsize_32) {
|
|
tmp &= 0xFFFF;
|
|
}
|
|
|
|
{
|
|
ADDR addrT = {0};
|
|
|
|
addrT = *lpaddr;
|
|
ADDR_IS_LI(addrT) = FALSE;
|
|
addrT.emi = 0;
|
|
offAddr ( addrT ) = (UOFFSET) tmp;
|
|
|
|
OutputSymbol (
|
|
hpidLocal,
|
|
htidLocal,
|
|
!! ( dop & dopSym ),
|
|
FALSE,
|
|
&addrT,
|
|
CV_REG_CS,
|
|
opsize_32 ? 4 : 2,
|
|
lpaddr,
|
|
&lpchOperands, &cchOperands
|
|
);
|
|
}
|
|
break;
|
|
|
|
case UBYT: /* unsigned byte for int/in/out */
|
|
/*
|
|
* For floating point emulation interupts in dos, we need
|
|
* to output the equivalent fp instructions as comments
|
|
*/
|
|
|
|
if ((opcode == 0xCD) && (*pMem >= 0x34) && (*pMem <= 0x3D)) {
|
|
BYTE bT = *pMem;
|
|
|
|
CalcFPInt (
|
|
hpid, htid,
|
|
FullDisasm,
|
|
dop, lpaddr, cbMax,
|
|
rgchComment, cchComment );
|
|
OutputHexString ( &lpchOperands, &cchOperands, &bT, 1);
|
|
}
|
|
else {
|
|
OutputHexString ( &lpchOperands, &cchOperands, pMem, 1);
|
|
pMem++;
|
|
}
|
|
break;
|
|
|
|
case IB: /* operand is immediate byte */
|
|
if ((opcode & ~1) == 0xd4) { /* postop for AAD/AAM is 0x0a */
|
|
if (*pMem++ != 0x0a) /* test post-opcode byte */
|
|
OutputString ( &lpchOperands, &cchOperands, dszRESERVED );
|
|
break;
|
|
}
|
|
olen = 1; /* set operand length */
|
|
goto DoImmed;
|
|
|
|
case IW: /* operand is immediate word */
|
|
olen = 2; /* set operand length */
|
|
|
|
case IV: /* operand is word or dword */
|
|
DoImmed:
|
|
OutputHexValue ( &lpchOperands, &cchOperands, pMem, olen, FALSE );
|
|
pMem += olen;
|
|
break;
|
|
|
|
case OFFS: /* operand is offset */
|
|
/*
|
|
* Put out the size of the item the offset points to
|
|
*/
|
|
|
|
if ( opcode & 1 ) {
|
|
EAsize[0] = olen;
|
|
if ( olen == 2 ) {
|
|
OutputString ( &lpchOperands, &cchOperands, "word ptr " );
|
|
} else {
|
|
OutputString ( &lpchOperands, &cchOperands, "dword ptr " );
|
|
}
|
|
} else {
|
|
EAsize[0] = 1;
|
|
OutputString ( &lpchOperands, &cchOperands, "byte ptr " );
|
|
}
|
|
|
|
/*
|
|
* if address length is dword
|
|
*/
|
|
|
|
if (alen == 4) {
|
|
EAaddr[0] = *(long *)pMem; /* get the dword as address */
|
|
} else {
|
|
EAaddr[0] = *(WORD *)pMem; /* get a word as address */
|
|
}
|
|
|
|
if (PchSegOvr) {
|
|
OutputString( &lpchOperands, &cchOperands, PchSegOvr );
|
|
}
|
|
|
|
*lpchOperands++ = '['; /* ] */
|
|
cchOperands -= 1;
|
|
|
|
{
|
|
ADDR addrT = {0};
|
|
|
|
if ( alen == 4 ) {
|
|
ADDRLIN32 ( addrT );
|
|
} else {
|
|
ADDRSEG16 ( addrT );
|
|
}
|
|
|
|
offAddr ( addrT ) = (UOFFSET) EAaddr [ 0 ];
|
|
|
|
if ( PchSegOvr ) {
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue ( hpid, htid, segOvrIndx,
|
|
(LONG) (LPW) &segAddr ( addrT ) );
|
|
}
|
|
OutputSymbol (
|
|
hpidLocal,
|
|
htidLocal,
|
|
!! ( dop & dopSym ), PchSegOvr != NULL,
|
|
&addrT, segOvrIndx, alen, lpaddr, &lpchOperands,
|
|
&cchOperands);
|
|
} else {
|
|
WORD wT = 0;
|
|
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
CV_REG_DS,
|
|
(LONG) (LPW) &segAddr ( addrT )
|
|
);
|
|
}
|
|
if (reg16[rm] == CV_REG_BP) {
|
|
pchEAseg[0] = dszSS_;
|
|
EAseg[0] = CV_REG_SS;
|
|
}
|
|
|
|
if ( FullDisasm ) {
|
|
if (rm < 4) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
reg16_2[rm],
|
|
(LONG) (LPW) &wT
|
|
);
|
|
EAaddr[0] += wT;
|
|
}
|
|
if ( mod == 1 ) {
|
|
EAaddr[0] += *( (char*)pMem);
|
|
} else if ( mod == 2 ) {
|
|
EAaddr[0] += *( (int*)pMem);
|
|
}
|
|
}
|
|
|
|
OutputSymbol (
|
|
hpidLocal,
|
|
htidLocal,
|
|
!! ( dop & dopSym ),
|
|
FALSE,
|
|
&addrT,
|
|
iregNone,
|
|
alen,
|
|
lpaddr,
|
|
&lpchOperands, &cchOperands
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
pMem += alen; /* [ */
|
|
*lpchOperands++ = ']';
|
|
cchOperands -= 1;
|
|
break;
|
|
|
|
case GROUP:
|
|
/*
|
|
* operand is of group 1,2,4,6 or 8
|
|
* output opcode symbol
|
|
*/
|
|
|
|
OutputString ( &lpchOpcode, &cchOpcode, group [*action++][ttt] );
|
|
break;
|
|
|
|
case GROUPT:
|
|
/*
|
|
* operand is of group 3,5 or 7
|
|
*/
|
|
|
|
indx = *action; /* get indx into group from action */
|
|
ttt = BIT53(*pMem);
|
|
goto doGroupT;
|
|
|
|
case EGROUPT: /* x87 ESC (D8-DF) group index */
|
|
|
|
indx = BIT20(opcode) * 2; /* get group index from opcode */
|
|
if (mod == 3) { /* some operand variations exists */
|
|
/* for x87 and mod == 3 */
|
|
++indx; /* take the next group table entry */
|
|
if (indx == 3) { /* for x87 ESC==D9 and mod==3 */
|
|
if (ttt > 3) { /* for those D9 instructions */
|
|
indx = 12 + ttt;/* offset index to table by 12 */
|
|
ttt = rm; /* set secondary index to rm */
|
|
}
|
|
}
|
|
else if (indx == 7) { /* for x87 ESC==DB and mod==3 */
|
|
if (ttt == 4) /* only valid if ttt==4 */
|
|
ttt = rm; /* set secondary group table index */
|
|
else
|
|
ttt = 7; /* no an x87 instruction */
|
|
}
|
|
}
|
|
doGroupT:
|
|
/* handle group with different types of operands */
|
|
|
|
OutputString ( &lpchOpcode, &cchOpcode,
|
|
groupt[indx][ttt].instruct );
|
|
action = actiontbl + groupt[indx][ttt].opr;
|
|
/* get new action */
|
|
break;
|
|
|
|
case OPC0F: /* secondary opcode table (opcode 0F) */
|
|
opcodeT = opcode = *pMem++; /* get real opcode */
|
|
if (opcode < 0x10) /* for the first 10 opcodes */
|
|
opcodeT += 256;
|
|
else if (opcode > 0x1f && opcode < 0x27)
|
|
opcodeT += 256 - (0x20 - 0x10);
|
|
else if (opcode > 0x7c && opcode < 0xd0)
|
|
opcodeT += 256 - (0x20 - 0x10) - (0x7d -0x27);
|
|
else
|
|
opcodeT = 260; /* all non existing opcodes */
|
|
goto getNxtByte1;
|
|
|
|
case ADR_OVR: /* address override */
|
|
mode_32 = !mode_32; /* override addressing mode */
|
|
alen = (mode_32 + 1) << 1; /* toggle address length */
|
|
goto getNxtByte;
|
|
|
|
case OPR16:
|
|
opsize_32 = 0;
|
|
olen = 2;
|
|
break;
|
|
|
|
case OPR_OVR: /* operand size override */
|
|
opsize_32 = !opsize_32; /* override operand size */
|
|
olen = (opsize_32 + 1) << 1; /* toggle operand length */
|
|
goto getNxtByte;
|
|
|
|
case SEG_OVR: /* handle segment override */
|
|
|
|
/* Pointer should be dgroup based */
|
|
|
|
lpchSegOvr = RgchSegOvr;
|
|
cbT = sizeof(RgchSegOvr);
|
|
OutputString( &lpchSegOvr, &cbT, distbl [ opcode ].instruct );
|
|
RgchSegOvr [ 3 ] = '\0';
|
|
PchSegOvr = RgchSegOvr; /* save seg ovr string */
|
|
segOvrIndx = GETINDX ( opcode );
|
|
lpchOpcode -= strlen(RgchSegOvr);
|
|
cchOpcode += strlen(RgchSegOvr);
|
|
*lpchOpcode = 0;
|
|
goto getNxtByte;
|
|
|
|
case BOP:
|
|
if (*pMem == 0xc4) {
|
|
cchOpcode += lpchOpcode - rgchOpcode;
|
|
lpchOpcode = rgchOpcode;
|
|
OutputString(&lpchOpcode, &cchOpcode, dszBOP);
|
|
pMem++;
|
|
} else {
|
|
action = actiontbl + O_fReg_Modrm;
|
|
}
|
|
break;
|
|
|
|
case REP: /* handle rep/lock prefixes */
|
|
inREP = 1; // kludge!
|
|
getNxtByte:
|
|
opcodeT = opcode = *pMem++; /* next byte is opcode */
|
|
if (inREP
|
|
&&
|
|
(opcodeT == 0xa6 || opcodeT == 0xa7
|
|
|| opcodeT == 0xae || opcodeT == 0xaf)
|
|
)
|
|
{
|
|
OutputString ( &lpchOpcode, &cchOpcode, "E");
|
|
}
|
|
if ( rgchOpcode != lpchOpcode ) {
|
|
/***
|
|
*lpchOpcode++ = ' ';
|
|
cchOpcode -= 1;
|
|
***/
|
|
OutputString ( &lpchOpcode, &cchOpcode, " ");
|
|
}
|
|
getNxtByte1:
|
|
action = actiontbl + distbl [ opcodeT ].opr;
|
|
OutputString ( &lpchOpcode, &cchOpcode, distbl [opcodeT].instruct);
|
|
inREP = 0; // un-kludge!
|
|
break;
|
|
|
|
case O_GROUP5:
|
|
EAsize [ 0 ] = olen;
|
|
break;
|
|
|
|
default: /* opcode has no operand */
|
|
|
|
break;
|
|
}
|
|
|
|
switch ( action2 ) { /* secondary action */
|
|
|
|
case MRM: /* generate modrm for later use */
|
|
if (!mrm) { /* ignore if it has been generated */
|
|
cbT = sizeof(rgchModrm);
|
|
DIdoModrm ( hpid, htid, FullDisasm, lpaddr, dop, &lpchModrm, &cbT );
|
|
mrm = TRUE; /* remember its generation */
|
|
}
|
|
break;
|
|
|
|
case COM: /* insert a comma after operand */
|
|
*lpchOperands++ = ',';
|
|
cchOperands -= 1;
|
|
break;
|
|
|
|
case END: /* end of instruction */
|
|
end = TRUE;
|
|
break;
|
|
}
|
|
|
|
} while ( !end ); /* loop til end of instruction */
|
|
|
|
*lpcbUsed = pMem - rgb;
|
|
}
|
|
|
|
void
|
|
CalcFPInt (
|
|
HPID hpid,
|
|
HTID htid,
|
|
BOOL FullDisasm,
|
|
DOP dop,
|
|
LPADDR lpaddr,
|
|
int cbMax,
|
|
LPCH lpch,
|
|
int cch
|
|
)
|
|
{
|
|
UCHAR FAR *pMemT = pMem;
|
|
UCHAR rgb [ MAXL ];
|
|
UCHAR bOp = *pMem;
|
|
|
|
if ( bOp == 0x3D ) {
|
|
OutputString(&lpch, &cch, dszFWAIT );
|
|
pMem += 1;
|
|
}
|
|
else {
|
|
int cbUsed = 0;
|
|
char rgchOpcode [ 16 ];
|
|
char rgchOperands [ 80 ];
|
|
int ich = 0;
|
|
|
|
_fmemset ( rgchOpcode, 0, sizeof ( rgchOpcode ) );
|
|
_fmemset ( rgchOperands, 0, sizeof ( rgchOperands ) );
|
|
|
|
if ( bOp == 0x3C ) {
|
|
rgb [ 0 ] = (UCHAR) ( rgbOverride [ *(pMem + 1) >> 6 ] );
|
|
rgb [ 1 ] = (UCHAR) ( *(pMem + 1) | 0xC0 );
|
|
_fmemcpy ( &rgb [ 2 ], pMem + 2, cbMax - 2 );
|
|
} else {
|
|
rgb [ 0 ] = (UCHAR) ( bOp + 0xA4 );
|
|
_fmemcpy ( &rgb [ 1 ], pMem + 1, cbMax - 2 );
|
|
}
|
|
|
|
CalcMain (
|
|
hpid,
|
|
htid,
|
|
FullDisasm,
|
|
dop,
|
|
lpaddr,
|
|
rgb,
|
|
cbMax - 1,
|
|
&cbUsed,
|
|
rgchOpcode, sizeof(rgchOpcode),
|
|
rgchOperands, sizeof(rgchOperands),
|
|
NULL, 0
|
|
);
|
|
|
|
while ( rgchOpcode [ ich ] != '\0' ) {
|
|
*(lpch + ich ) = rgchOpcode [ ich ];
|
|
ich += 1;
|
|
}
|
|
|
|
while ( ich < 9 ) {
|
|
*(lpch + ich) = ' ';
|
|
ich += 1;
|
|
}
|
|
|
|
while ( rgchOperands [ ich - 9 ] != '\0' ) {
|
|
*(lpch + ich) = rgchOperands [ ich - 9 ];
|
|
ich += 1;
|
|
}
|
|
|
|
pMem = pMemT + cbUsed;
|
|
}
|
|
}
|
|
|
|
void
|
|
DIdoModrm (
|
|
HPID hpid,
|
|
HTID htid,
|
|
BOOL FullDisasm,
|
|
LPADDR lpaddr,
|
|
DOP dop,
|
|
LPLPCH lplpchBuf,
|
|
int * pcch
|
|
)
|
|
{
|
|
int mrm; /* modrm byte */
|
|
PCH src; /* source string */
|
|
int sib;
|
|
int ss;
|
|
int ind;
|
|
int oldrm;
|
|
int fSymbol = FALSE;
|
|
ULONG wT;
|
|
|
|
BOOL fRegIndirect = FALSE;
|
|
int iScale;
|
|
|
|
mrm = *pMem++; /* get the mrm byte from instruction */
|
|
mod = BIT76(mrm); /* get mod */
|
|
ttt = BIT53(mrm); /* get reg - used outside routine */
|
|
rm = BIT20(mrm); /* get rm */
|
|
|
|
if (mod == 3) { /* register only mode */
|
|
src = ®tab[rm * 2]; /* point to 16-bit register */
|
|
if (EAsize[0] > 1) {
|
|
src += 16; /* point to 16-bit register */
|
|
if (EAsize[0] > 2)
|
|
*(*lplpchBuf)++ = (char) ( fUpper ? 'E' : 'e' );/* make it a 32bit register */
|
|
}
|
|
*(*lplpchBuf)++ = *src++; /* copy register name */
|
|
*(*lplpchBuf)++ = *src;
|
|
EAsize[0] = 0; /* no EA value to output */
|
|
PchSegOvr = NULL;
|
|
return;
|
|
}
|
|
|
|
if (mode_32) { /* 32-bit addressing mode */
|
|
*(*lplpchBuf)++ = '['; /* ] */
|
|
|
|
oldrm = rm;
|
|
if (rm == 4) { /* rm == 4 implies sib byte */
|
|
|
|
// register indirect
|
|
|
|
sib = *pMem++; /* get s_i_b byte */
|
|
rm = BIT20(sib); /* return base */
|
|
ind = BIT53(sib);
|
|
|
|
if (ind != 4) {
|
|
|
|
// not ebp
|
|
// with offset
|
|
|
|
OutputString(lplpchBuf, pcch, mrmtb32[ind]);
|
|
ss = 1 << BIT76(sib);
|
|
if (ss != 1) {
|
|
|
|
// scaled
|
|
|
|
*(*lplpchBuf)++ = '*';
|
|
*(*lplpchBuf)++ = (char)(ss + '0');
|
|
}
|
|
*(*lplpchBuf)++ = '+';
|
|
fRegIndirect = TRUE;
|
|
iScale = ss;
|
|
}
|
|
}
|
|
|
|
|
|
if ( mod == 0 && rm == 5) {
|
|
ADDR addrT = {0};
|
|
|
|
// memory indirect
|
|
|
|
if (fRegIndirect && iScale == 4) {
|
|
FDwordTable = TRUE;
|
|
}
|
|
|
|
ADDRLIN32 ( addrT );
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
CV_REG_SS,
|
|
(LONG) (LPW) &( segAddr ( addrT ) )
|
|
);
|
|
}
|
|
EAaddr[0] = (long) ( *(unsigned long *) pMem );
|
|
offAddr ( addrT ) = (UOFFSET) EAaddr[0];
|
|
|
|
OutputSymbol (
|
|
hpidLocal,
|
|
htidLocal,
|
|
!! ( dop & dopSym ),
|
|
FALSE,
|
|
&addrT,
|
|
iregNone,
|
|
4,
|
|
lpaddr,
|
|
lplpchBuf, pcch
|
|
);
|
|
pMem += 4;
|
|
} else if ( (rm == 5) && ( (mod == 1) || (mod == 2) ) ) {
|
|
ADDR addrT = {0};
|
|
CHAR rgchSymbol[60];
|
|
LPCH lpchSymbol;
|
|
LONG displacement;
|
|
ADDRLIN32 ( addrT );
|
|
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue ( hpid,
|
|
htid,
|
|
CV_REG_SS,
|
|
(LONG) (LPW) &(segAddr (addrT)));
|
|
}
|
|
if ( mod == 2) {
|
|
EAaddr [ 0 ] = (long) ( *(long *) pMem );
|
|
} else { /* mod == 1 */
|
|
EAaddr [ 0 ] = (long) ( *(PCH) pMem );
|
|
}
|
|
|
|
offAddr ( addrT ) = (UOFFSET) EAaddr [ 0 ];
|
|
|
|
pchEAseg[0] = dszSS_;
|
|
EAseg[0] = CV_REG_SS;
|
|
|
|
if ( FullDisasm ) {
|
|
if ( dop & dopSym ) {
|
|
lpchSymbol = ObtainSymbol(&addrT, sopStack, lpaddr,
|
|
rgchSymbol, &displacement);
|
|
|
|
if ( fSymbol = (lpchSymbol != NULL ) ) {
|
|
OutputIString ( lplpchBuf, pcch, rgchSymbol );
|
|
pMem += ( mod == 1 ) ? 1 : (mode_32 + 1 ) * 2;
|
|
}
|
|
}
|
|
|
|
GetRegisterValue( hpid, htid, CV_REG_EBP, (LONG) &wT);
|
|
EAaddr[0] += wT;
|
|
}
|
|
if ( !fSymbol ) {
|
|
OutputString( lplpchBuf, pcch, mrmtb32[rm]);
|
|
}
|
|
|
|
} else {
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
reg32[rm],
|
|
(LONG) (LPW) &(EAaddr[0])
|
|
);
|
|
}
|
|
if (reg32[rm] == CV_REG_EBP || reg32[rm] == CV_REG_ESP) {
|
|
pchEAseg[0] = dszSS_;
|
|
}
|
|
EAseg[0] = CV_REG_SS;
|
|
OutputString(lplpchBuf, pcch, mrmtb32[rm]);
|
|
}
|
|
|
|
if ( FullDisasm ) {
|
|
if (oldrm == 4) { /* finish processing sib */
|
|
if (ind != 4) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
reg32[ind],
|
|
(LONG) (LPW) &(wT)
|
|
);
|
|
EAaddr[0] += wT * ss;
|
|
}
|
|
}
|
|
}
|
|
} else { /* 16-bit addressing mode */
|
|
*(*lplpchBuf)++ = '['; /* ] */
|
|
if ( mod == 0 && rm == 6 ) {
|
|
ADDR addrT = {0};
|
|
|
|
ADDRSEG16 ( addrT );
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
CV_REG_SS,
|
|
(LONG) (LPW) &( segAddr ( addrT ) )
|
|
);
|
|
}
|
|
EAaddr [ 0 ] = (long) ( *(unsigned short *) pMem );
|
|
pMem += 2;
|
|
|
|
offAddr ( addrT ) = (UOFFSET) EAaddr [ 0 ];
|
|
|
|
OutputSymbol (
|
|
hpidLocal,
|
|
htidLocal,
|
|
!! ( dop & dopSym ),
|
|
FALSE,
|
|
&addrT,
|
|
iregNone,
|
|
2,
|
|
lpaddr,
|
|
lplpchBuf, pcch
|
|
);
|
|
}
|
|
else if ( rm == 6 && ( mod == 1 || mod == 2 ) ) {
|
|
ADDR addrT = {0};
|
|
CHAR rgchSymbol [ 60 ];
|
|
LPCH lpchSymbol;
|
|
long displacement;
|
|
ADDRSEG16 ( addrT );
|
|
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
CV_REG_SS,
|
|
(LONG) (LPW) &( segAddr ( addrT ) )
|
|
);
|
|
}
|
|
|
|
if ( mod == 2 ) {
|
|
EAaddr [ 0 ] = (long) ( *(short *) pMem );
|
|
}
|
|
else { // ( mod == 1 )
|
|
EAaddr [ 0 ] = (long) ( *(PCH) pMem );
|
|
}
|
|
|
|
offAddr ( addrT ) = (UOFFSET) EAaddr [ 0 ];
|
|
|
|
pchEAseg[0] = dszSS_;
|
|
EAseg[0] = CV_REG_SS;
|
|
|
|
if ( FullDisasm ) {
|
|
if ( dop & dopSym ) {
|
|
lpchSymbol = ObtainSymbol (
|
|
&addrT,
|
|
sopStack,
|
|
lpaddr,
|
|
rgchSymbol,
|
|
&displacement );
|
|
|
|
if ( fSymbol = ( lpchSymbol != NULL ) ) {
|
|
|
|
OutputIString ( lplpchBuf, pcch, rgchSymbol );
|
|
pMem += ( mod == 1 ) ? 1 : ( mode_32 + 1 ) * 2;
|
|
}
|
|
}
|
|
|
|
GetRegisterValue( hpid, htid, CV_REG_EBP, (LONG) &wT);
|
|
EAaddr[0] += (wT & 0xffff);
|
|
}
|
|
|
|
if ( !fSymbol ) {
|
|
OutputString(lplpchBuf, pcch, mrmtb16[rm]);
|
|
}
|
|
}
|
|
else {
|
|
if ( FullDisasm ) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
reg16[rm],
|
|
(LONG) (LPW) &(EAaddr[0])
|
|
);
|
|
if (reg16[rm] == CV_REG_BP)
|
|
pchEAseg[0] = dszSS_;
|
|
EAseg[0] = CV_REG_SS;
|
|
if (rm < 4) {
|
|
GetRegisterValue (
|
|
hpid,
|
|
htid,
|
|
reg16_2[rm],
|
|
(LONG) (LPW) &(EAaddr[0])
|
|
);
|
|
}
|
|
}
|
|
OutputString(lplpchBuf, pcch, mrmtb16[rm]);
|
|
}
|
|
}
|
|
|
|
// output any displacement
|
|
|
|
if ( !fSymbol ) {
|
|
if (mod == 1) {
|
|
OutputHexValue(lplpchBuf, pcch, pMem, 1, TRUE);
|
|
pMem++;
|
|
}
|
|
else if (mod == 2) {
|
|
if (mode_32) {
|
|
OutputHexValue(lplpchBuf, pcch, pMem, 4, TRUE);
|
|
pMem += 4;
|
|
}
|
|
else {
|
|
OutputHexValue(lplpchBuf, pcch, pMem, 2, TRUE);
|
|
pMem += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !mode_32 ) {
|
|
EAaddr[0] &= 0xffff;
|
|
EAaddr[1] &= 0xffff;
|
|
}
|
|
|
|
*(*lplpchBuf)++ = ']';
|
|
|
|
return;
|
|
}
|
|
|
|
/*** OutputHexValue - output hex value
|
|
*
|
|
* Purpose:
|
|
* Output the value pointed by *lplpchBuf of the specified
|
|
* length. The value is treated as unsigned and all leading
|
|
* zeros are output. If fDisplacement is true, treat as signed
|
|
* and always prepend +/-.
|
|
*
|
|
* Input:
|
|
* *lplpchBuf - pointer to text buffer to fill
|
|
* *pchMemBuf - pointer to memory buffer to extract value
|
|
* length - length in bytes of value (1, 2, and 4 supported)
|
|
* fDisp - set if displacement to output '+'
|
|
*
|
|
* Output:
|
|
* *lplpchBuf - pointer updated to next text character
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
OutputHexValue (
|
|
LPLPCH lplpchBuf,
|
|
int * pcch,
|
|
PCH pchMemBuf,
|
|
int length,
|
|
int fDisp
|
|
)
|
|
{
|
|
long value;
|
|
int index;
|
|
char digit[8];
|
|
|
|
if ( length == 1 ) {
|
|
value = (long) (*(PCH)pchMemBuf);
|
|
}
|
|
else if ( length == 2 ) {
|
|
value = (long) (*(short FAR *)pchMemBuf);
|
|
}
|
|
else {
|
|
value = *(long FAR *)pchMemBuf;
|
|
}
|
|
|
|
if ( fDisp ) {
|
|
if ( value < 0 ) {
|
|
*(*lplpchBuf)++ = '-';
|
|
value = -value;
|
|
}
|
|
else if ( value > 0 ) {
|
|
*(*lplpchBuf)++ = '+';
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (index = 7; index != -1; index--) {
|
|
digit[index] = (char)(value & 0xf);
|
|
value >>= 4;
|
|
}
|
|
|
|
index = 8 - ( length * 2 );
|
|
|
|
while ( index < 8 ) {
|
|
*(*lplpchBuf)++ = hexdigit [ digit [ index++ ] ];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** OutputHexString - output hex string
|
|
*
|
|
* Purpose:
|
|
* Output the value pointed by *lplpchMemBuf of the specified
|
|
* length. The value is treated as unsigned and leading
|
|
* zeroes are printed.
|
|
*
|
|
* Input:
|
|
* *lplpchBuf - pointer to text buffer to fill
|
|
* *pchValue - pointer to memory buffer to extract value
|
|
* length - length in bytes of value
|
|
*
|
|
* Output:
|
|
* *lplpchBuf - pointer updated to next text character
|
|
* *lplpchMemBuf - pointer update to next memory byte
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
OutputHexString (
|
|
LPLPCH lplpchBuf,
|
|
int * pcch,
|
|
PCH pchValue,
|
|
int length
|
|
)
|
|
{
|
|
unsigned char chMem;
|
|
|
|
pchValue += length;
|
|
while ( length-- ) {
|
|
chMem = *--pchValue;
|
|
*(*lplpchBuf)++ = hexdigit[chMem >> 4];
|
|
*(*lplpchBuf)++ = hexdigit[chMem & 0x0f];
|
|
}
|
|
}
|
|
|
|
/*** OutputAddr - output address package
|
|
*
|
|
* Purpose:
|
|
* Output the address pointed to by lpaddr.
|
|
*
|
|
* Input:
|
|
* *lplpchBuf - pointer to text buffer to fill
|
|
* lpaddr - Standard address package.
|
|
*
|
|
* Output:
|
|
* *lplpchBuf - pointer updated to next text character
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
OutputAddr (
|
|
LPLPCH lplpchBuf,
|
|
int * pcch,
|
|
LPADDR lpaddr,
|
|
int alen,
|
|
BOOL fSeg
|
|
)
|
|
{
|
|
ADDR addr = *lpaddr;
|
|
|
|
if (fSeg) {
|
|
OutputString( lplpchBuf, pcch, "0x" );
|
|
OutputHexString ( lplpchBuf, pcch, (LPCH) &( segAddr ( addr ) ), 2 );
|
|
*(*lplpchBuf)++ = ADDR_IS_REAL(*lpaddr) ? '#' : ':';
|
|
*pcch -= 1;
|
|
}
|
|
OutputString( lplpchBuf, pcch, "0x" );
|
|
OutputHexString ( lplpchBuf, pcch, (LPCH) &offAddr ( addr ), alen );
|
|
}
|
|
|
|
/*** OutputHexCode - output hex code
|
|
*
|
|
* Purpose:
|
|
* Output the code pointed by lpchMemBuf of the specified
|
|
* length. The value is treated as unsigned and leading
|
|
* zeroes are printed. This differs from OutputHexString
|
|
* in that bytes are printed from low to high addresses.
|
|
*
|
|
* Input:
|
|
* *lplpchBuf - pointer to text buffer to fill
|
|
* lpchMemBuf - pointer to memory buffer to extract value
|
|
* length - length in bytes of value
|
|
*
|
|
* Output:
|
|
* *lplpchBuf - pointer updated to next text character
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
OutputHexCode (
|
|
LPLPCH lplpchBuf,
|
|
LPCH lpchMemBuf,
|
|
int length
|
|
)
|
|
{
|
|
unsigned char chMem;
|
|
|
|
while (length--) {
|
|
chMem = *lpchMemBuf++;
|
|
*(*lplpchBuf)++ = hexdigit[chMem >> 4];
|
|
*(*lplpchBuf)++ = hexdigit[chMem & 0x0f];
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
OutputString(
|
|
LPLPCH lplpchBuf,
|
|
int * lpcch,
|
|
LPCH lpchString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will copy the string pointed to by lpchString to the
|
|
buffer pointed to by lplpchBuf with the following restrictions:
|
|
|
|
1. The string will be converted to uppercase if need be while
|
|
being copied.
|
|
2. We will cut off the string when the destination buffer is filled
|
|
3. We will guarrenttee that the destination buffer is termiatned
|
|
with a 0.
|
|
|
|
Arguments:
|
|
|
|
lplpchBuf - Supplies a pointer to the buffer to copy into, pointer is
|
|
- Returns to point to after last character copied
|
|
lpcch - Supplies a pointer to lenght of destination buffer
|
|
lpchString - Supplies a pointer to the string to be copied
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
int cb;
|
|
|
|
/*
|
|
* Assert on bad input values
|
|
*/
|
|
assert( lpchString != NULL);
|
|
assert( lplpchBuf != NULL );
|
|
assert( lpcch != NULL );
|
|
assert( *lplpchBuf != NULL );
|
|
|
|
/*
|
|
* If no room left in the buffer -- return
|
|
*/
|
|
|
|
if (*lpcch == 0) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Copy over as much of the string as will fit
|
|
*/
|
|
|
|
cb = strlen(lpchString);
|
|
if (cb + 1 > *lpcch) {
|
|
cb = *lpcch - 1;
|
|
}
|
|
|
|
strncpy(*lplpchBuf, lpchString, cb);
|
|
(*lplpchBuf)[cb] = 0;
|
|
|
|
if ( fUpper ) {
|
|
_strupr(*lplpchBuf);
|
|
} else {
|
|
_strlwr(*lplpchBuf);
|
|
}
|
|
*lplpchBuf += cb;
|
|
*lpcch -= cb;
|
|
return;
|
|
} /* OutputString() */
|
|
|
|
void
|
|
OutputIString(
|
|
LPLPCH lplpchBuf,
|
|
int * pcch,
|
|
LPCH lpchString
|
|
)
|
|
{
|
|
int cb;
|
|
|
|
cb = strlen(lpchString);
|
|
if (cb + 1 > *pcch) {
|
|
cb = *pcch - 1;
|
|
}
|
|
strncpy(*lplpchBuf, lpchString, cb);
|
|
*lplpchBuf += cb;
|
|
*pcch -= cb;
|
|
**lplpchBuf = 0;
|
|
return;
|
|
} /* OutputIString() */
|