📄 tcwiz1.cpp
字号:
// File : TcWiz1.Cpp
// Implementation of the DecodeSwitchStatement function.
// Implementation file of TcWizard.h
//
#include <dos.h>
#include <stdio.h>
#include <assert.h>
#include <alloc.h>
#include <conio.h>
#include "Disc.h"
#include "TcWizard.h"
#include "Disasm.h"
/*----------------------------------------------------------------------
FillSwitchInfo - Only to fill the info into the structure passed.
----------------------------------------------------------------------*/
void TcWizard::FillSwitchInfo(Byte far *Inst,InstInfo &inst,SwitchInfo &SwInfo)
{
int SwitchType = IsSwitchStatement(FP_OFF(Inst));
InstInfo tinst;
if (SwitchType==C_SWITCH)
{
// An ordinary switch is coded like given below.
// MOV CX,NumClauses
// MOV BX,SwitchTable
// CS:
// MOV AX,[BX]
// CMP AX,...
// ...
// LOOP label
// JMP AddressOfDefault.
// so, to find the address of the switch table, use BX
// to find the address of the no. of switch clauses, use CX.
SwInfo.NumClauses = Regs[REG_CX].ValueFromHex();
Word Segment = FP_SEG(Inst); // CS
SwInfo.SwitchTable= (Byte far *)MK_FP(Segment,Regs[REG_BX].ValueFromHex());
FindInstruction(Inst,JMP,&tinst);
SwInfo.DefaultAddress = tinst.Data11;
SwInfo.DeleteAfterUse=0;
}
else if (SwitchType==C_SWITCH_ORDERED)
{
// An ordered switch is coded like given below.
// MOV Reg,val
// CMP Reg,MAXVAL where MAXVAL gives the count of the 'case' statements.
// JA AddressOfDefault
// SHL Reg,1
// CS:
// JMP [Reg+AddressOfSwitchTable]
// Now we are in the "CMP Reg,MAXVAL" instruction.
SwInfo.NumClauses = inst.Data21+1;
Disasm d; d.SetCodePtr(CodePtr);
int InstLen;
d.TraceInst(Inst,InstLen); Inst+= InstLen; // Skip the CMP instruction.
d.TraceInst(Inst,InstLen); Inst+= InstLen; // Trace the JA instruction.
SwInfo.DefaultAddress = d.CurInst.Data11;
d.TraceInst(Inst,InstLen); Inst+= InstLen; // Ignore the next SHL & CS:
d.TraceInst(Inst,InstLen); Inst+= InstLen; // instructions.
Word Segment = FP_SEG(Inst); // CS
d.TraceInst(Inst,InstLen);
Word far *Addrs = (Word far *)MK_FP(Segment,d.CurInst.Data12);
int *tab = new int[(SwInfo.NumClauses+1)*2];
assert(tab!=NULL);
for(int i=0;i<SwInfo.NumClauses;i++) tab[i] = i;
for(int j=0;i<2*SwInfo.NumClauses;i++,j++) tab[i] = Addrs[j];
SwInfo.SwitchTable= (Byte far *)tab;
// Memory allocated here is to be freed by 'DecodeSwitchStatement' fn.
SwInfo.DeleteAfterUse=1;
}
}
/*----------------------------------------------------------------------
FindInstruction - finds the next matching instructin and stores it
in the InstInfo passed.
Also returns the address of the instruction.
----------------------------------------------------------------------*/
Byte far *TcWizard::FindInstruction(Byte far *Inst,Byte Instruc,InstInfo *inst,int *LenPtr)
{
Disasm d;
d.SetCodePtr(CodePtr);
int InstLen=0;
do
{
Inst += InstLen;
d.TraceInst(Inst,InstLen);
}while(d.CurInst.Instr != Instruc);
*inst = d.CurInst;
if (LenPtr) *LenPtr = InstLen;
return Inst;
}
/*----------------------------------------------------------------------
DecodeSwitchStatement - Decodes the switch statement and prints it into
the string list passed.
----------------------------------------------------------------------*/
Byte far *TcWizard::DecodeSwitchStatement(SwitchInfo &SwInfo,int How,StringList *sList,Word BlockEndAddress)
{
int i;
String s_LineBuffer;
char *LineBuffer = (char *)s_LineBuffer;
InstInfo inst;
Dword BlockSize;
Byte far *Inst;
// How to find the end of the switch statement? Here we check for the
// addresses given in the JMPs at the end of each CASE block, and find
// the address which is nearest and after the address of DEFAULT stat.
// (Confusing? Think for some time. 'tis a weird logic, but works here.)
Word EndOfSwitch = 0xffff;
Word *SwitchAddrs = (Word *)new Word[SwInfo.NumClauses+1];
assert(SwitchAddrs);
for(i=0;i<SwInfo.NumClauses;i++)
{
// 2 - denotes the sizeof(int). Only integers can be used in SWITCH.
Word addr = *(Word far *)(SwInfo.SwitchTable+i*2+SwInfo.NumClauses*2);
for(int j=0;j<i;j++)
if (addr<SwitchAddrs[j]) break;
for(int k=SwInfo.NumClauses;k>j;k--) SwitchAddrs[k] = SwitchAddrs[k-1];
SwitchAddrs[j] = addr;
Inst = (Byte far *)MK_FP(FP_SEG(CodePtr),addr);
BlockSize = FindInstruction(Inst,JMP,&inst) - Inst;
if (inst.Data11>=SwInfo.DefaultAddress && inst.Data11<EndOfSwitch)
EndOfSwitch = inst.Data11;
}
if (EndOfSwitch>BlockEndAddress) EndOfSwitch=BlockEndAddress;
SwitchAddrs[SwInfo.NumClauses] = SwInfo.DefaultAddress;
// Now we have the EndOfSwitch address in out hands.
Disasm d;
d.SetCodePtr(CodePtr);
for(i=0;i<SwInfo.NumClauses;i++)
{
Word addr = SwitchAddrs[i];
Word far *AddrTable = ((Word far *)SwInfo.SwitchTable)+SwInfo.NumClauses;
for(int j=0;j<SwInfo.NumClauses;j++)
if (AddrTable[j]==addr) break;
// 2 - denotes the sizeof(int). Only integers can be used in SWITCH.
sprintf(LineBuffer,"case %d :",(int)*((Word far *)(SwInfo.SwitchTable+j*2)));
InstAddr=addr;
Output(LineBuffer,How,sList);
Inst = (Byte far *)MK_FP(FP_SEG(CodePtr),addr);
BlockSize = SwitchAddrs[i+1]-SwitchAddrs[i];
int InstLen;
d.TraceInst(Inst+BlockSize-2,InstLen); //2=sizeof(JMP short_address)
int BreakPresent=0;
// If a BREAK is present in the block, we shall give it here, but if
// it is terminated by a GOTO to another place, include it in the
// block to be translated.
if (d.CurInst.Instr==JMP && d.CurInst.Data11==EndOfSwitch)
{
BreakPresent=1;
BlockSize -= InstLen;
}
int tStackTop = StackTop;
TranslateBlock(Inst,BlockSize,How,sList);
StackTop = tStackTop; Stack[StackTop]="";
if (BreakPresent) Output("break;",How,sList);
// How to find the end of the switch statement? Here we check for the
// addresses given in the JMPs at the end of each CASE block, and find
// the address which is nearest and after the address of DEFAULT stat.
// (Confusing? Think for some time. 'tis a weird logic, but works here.)
if (inst.Data11>SwInfo.DefaultAddress && inst.Data11<EndOfSwitch)
EndOfSwitch = inst.Data11;
}
InstAddr=SwInfo.DefaultAddress;
Output("default :",How,sList);
Inst = (Byte far *)MK_FP(FP_SEG(CodePtr),SwInfo.DefaultAddress);
BlockSize = EndOfSwitch - SwInfo.DefaultAddress;
TranslateBlock(Inst,BlockSize,How,sList);
// inst contains the final JMP to outside the switch statement.
Inst = (Byte far *)MK_FP(FP_SEG(CodePtr),EndOfSwitch);
delete[] SwitchAddrs;
if (SwInfo.DeleteAfterUse)
{
delete[] ((void *)SwInfo.SwitchTable);
SwInfo.SwitchTable=NULL;
}
return Inst;
}
/*----------------------------------------------------------------------
GetReg - called to get the string containing the register's contents.
This function checks if the string is empty and gives an error if so.
-----------------------------------------------------------------------*/
String &TcWizard::GetReg(int whichReg)
{
if (Regs[whichReg].IsEmpty())
{
sprintf(errorStr,"Contents of empty register being accessed at %X",InstAddr);
ErrorList.Add(errorStr);
}
return Regs[whichReg];
}
/*
[-----------------------------------------------------------------------]
[ GetLabel - returns 1 if the Address passed corresponds to a label ]
[ and also stores the label name in the string passed. ]
[-----------------------------------------------------------------------]
*/
int TcWizard::GetLabel(Word Address,String &s)
{
register int i,labelcount;
((char *)s)[0]=0;
// bsearch(&Address,LabelTable,NumLabels,sizeof(Word),sortFunc);
for(i=0,labelcount=1;i<NumBlocks;i++)
{
if (BlockTable[i].Type==C_GOTO)
{
labelcount++;
if (BlockTable[i].Address==Address)
{
s = "Label";
s += labelcount;
return 1;
}
}
}
return 0;
}
/*----------------------------------------------------------------------
Procedures for supporting the long-int datatype are below.
----------------------------------------------------------------------*/
/*----------------------------------------------------------------------
IsLongInt - returns 1 if the address given is part of any known long-int.
Uses the GlobalVars & LocalVars variable-lists.
----------------------------------------------------------------------*/
int TcWizard::IsLongInt(Variable &v1)
{
Variable v2; int v2Type;
// Is it part of any known variable?
if (LocalVars.PartOfAnyVariable(v1,v2,v2Type) ||
GlobalVars.PartOfAnyVariable(v1,v2,v2Type))
return (v2Type==VAR_LONG);
return 0;
}
/*----------------------------------------------------------------------
FirstWordOfLongInt - returns 1 if the address given is the 1st word of
any known long-int. Uses the GlobalVars & LocalVars variable-lists.
----------------------------------------------------------------------*/
int TcWizard::IsFirstWordOfLongInt(Variable &v1)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -