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.
383 lines
10 KiB
383 lines
10 KiB
/**** SIMPLDIS.CPP - Generic BBT disassembler interface ********************
|
|
* *
|
|
* *
|
|
* Copyright <C> 1995, Microsoft Corp *
|
|
* *
|
|
* Created: September 18, 1995 by RafaelL *
|
|
* *
|
|
* Revision History: *
|
|
* *
|
|
* 1/16/96 KentF *
|
|
* Revised to provide a general purpose disassembler, using a C *
|
|
* interface and exposing no private types. *
|
|
* This implementation serializes access to the disassembler. *
|
|
* *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#include "pumap.h"
|
|
|
|
#include "axp.h"
|
|
#include "mips.h"
|
|
#include "ppc.h"
|
|
#include "x86.h"
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
|
|
#include "simpldis.h"
|
|
|
|
|
|
typedef
|
|
struct _LOCALDIS {
|
|
struct _LOCALDIS *next;
|
|
DIS *pdis;
|
|
int arch;
|
|
} LOCALDIS, *PLOCALDIS;
|
|
|
|
PLOCALDIS LdHead;
|
|
|
|
CRITICAL_SECTION CsEverything;
|
|
|
|
PFNCCHADDR PfnCchAddr;
|
|
PFNCCHFIXUP PfnCchFixup;
|
|
PFNCCHREGREL PfnCchRegrel;
|
|
PFNQWGETREG PfnQwGetreg;
|
|
|
|
PVOID Pv;
|
|
|
|
int
|
|
MapReg(
|
|
ARCHT archt,
|
|
int reg
|
|
)
|
|
{
|
|
switch(archt) {
|
|
case Simple_Arch_Mips:
|
|
return reg;
|
|
|
|
case Simple_Arch_X86:
|
|
switch(reg) {
|
|
case DISX86::regEax: return SimpleRegEax;
|
|
case DISX86::regEcx: return SimpleRegEcx;
|
|
case DISX86::regEdx: return SimpleRegEdx;
|
|
case DISX86::regEbx: return SimpleRegEbx;
|
|
case DISX86::regEsp: return SimpleRegEsp;
|
|
case DISX86::regEbp: return SimpleRegEbp;
|
|
case DISX86::regEsi: return SimpleRegEsi;
|
|
case DISX86::regEdi: return SimpleRegEdi;
|
|
}
|
|
return -1;
|
|
|
|
case Simple_Arch_AlphaAxp:
|
|
return reg;
|
|
|
|
case Simple_Arch_PowerPc:
|
|
return reg;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
size_t
|
|
CchAddr(
|
|
const DIS * pdis,
|
|
ADDR addr,
|
|
char * symbol,
|
|
size_t symsize,
|
|
DWORD *displacement
|
|
)
|
|
{
|
|
return PfnCchAddr(Pv, addr, symbol, symsize, displacement);
|
|
}
|
|
|
|
size_t
|
|
CchFixup(
|
|
const DIS * pdis,
|
|
ADDR addr,
|
|
size_t opsize,
|
|
char * symbol,
|
|
size_t symsize,
|
|
DWORD * displacement
|
|
)
|
|
{
|
|
return PfnCchFixup(Pv, pdis->Addr(), addr, opsize, symbol, symsize, displacement);
|
|
}
|
|
|
|
size_t
|
|
CchRegrel(
|
|
const DIS * pdis,
|
|
int reg,
|
|
DWORD offset,
|
|
char * symbol,
|
|
size_t symsize,
|
|
DWORD *displacement
|
|
)
|
|
{
|
|
return PfnCchRegrel(Pv, pdis->Addr(), MapReg(pdis->Archt(), reg), offset, symbol, symsize, displacement);
|
|
}
|
|
|
|
DWORD
|
|
DwGetreg(
|
|
const DIS * pdis,
|
|
int reg
|
|
)
|
|
{
|
|
DWORDLONG qw;
|
|
qw = PfnQwGetreg(Pv, MapReg(pdis->Archt(), reg));
|
|
return (DWORD)qw;
|
|
}
|
|
|
|
DIS *
|
|
GetPdis(
|
|
int arch
|
|
)
|
|
{
|
|
PLOCALDIS p;
|
|
|
|
for (p = LdHead; p; p = p->next) {
|
|
if (p->arch == arch) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!p) {
|
|
|
|
p = (PLOCALDIS)malloc(sizeof(LOCALDIS));
|
|
|
|
switch (arch) {
|
|
|
|
case Simple_Arch_Mips:
|
|
p->pdis = PdisNew(archtMips);
|
|
break;
|
|
|
|
case Simple_Arch_X86:
|
|
p->pdis = PdisNew(archtX86);
|
|
break;
|
|
|
|
case Simple_Arch_AlphaAxp:
|
|
p->pdis = PdisNew(archtAlphaAxp);
|
|
break;
|
|
|
|
case Simple_Arch_PowerPc:
|
|
p->pdis = PdisNew(archtPowerPc);
|
|
break;
|
|
|
|
default:
|
|
Assert(!"Wrong architecture");
|
|
free(p);
|
|
return NULL;
|
|
}
|
|
|
|
p->next = LdHead;
|
|
LdHead = p;
|
|
p->arch = arch;
|
|
|
|
p->pdis->PfncchaddrSet (PfnCchAddr ? CchAddr : NULL);
|
|
p->pdis->PfncchfixupSet (PfnCchFixup ? CchFixup : NULL);
|
|
p->pdis->PfncchregrelSet(PfnCchRegrel ? CchRegrel : NULL);
|
|
p->pdis->PfndwgetregSet (PfnQwGetreg ? DwGetreg : NULL);
|
|
|
|
}
|
|
|
|
return p->pdis;
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
WINAPI
|
|
SimplyDisassemble(
|
|
PBYTE pb,
|
|
const size_t cbMax,
|
|
const DWORD Address,
|
|
const int Architecture,
|
|
PSIMPLEDIS Sdis,
|
|
PFNCCHADDR pfnCchAddr,
|
|
PFNCCHFIXUP pfnCchFixup,
|
|
PFNCCHREGREL pfnCchRegrel,
|
|
PFNQWGETREG pfnQwGetreg,
|
|
const PVOID pv
|
|
)
|
|
{
|
|
DIS * pdis;
|
|
ADDR addr;
|
|
int fFoundEA = 0;
|
|
int cb;
|
|
TRMT trmt;
|
|
|
|
//
|
|
// use an interlock to control initialization of the
|
|
// critical section in order to remove the need for
|
|
// an initializtion function.
|
|
//
|
|
|
|
LONG l;
|
|
static LONG lock = -1;
|
|
|
|
|
|
wait:
|
|
if ((l = InterlockedIncrement(&lock)) == 0) {
|
|
InitializeCriticalSection(&CsEverything);
|
|
// don't use LONG_MIN, because this synchronization
|
|
// isn't really precise. There must be some
|
|
// negative number that is larger than the maximum
|
|
// plausible number of threads, but without danger
|
|
// of wrapping.
|
|
InterlockedExchange(&lock, -1000000);
|
|
} else {
|
|
InterlockedDecrement(&lock);
|
|
if (l > 0) {
|
|
Sleep(100);
|
|
goto wait;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// access to the disassembler is serialized,
|
|
// so the callback info may be stored in globals.
|
|
//
|
|
|
|
EnterCriticalSection(&CsEverything);
|
|
|
|
PfnCchAddr = pfnCchAddr;
|
|
PfnCchFixup = pfnCchFixup;
|
|
PfnCchRegrel = pfnCchRegrel;
|
|
PfnQwGetreg = pfnQwGetreg;
|
|
Pv = pv;
|
|
|
|
pdis = GetPdis(Architecture);
|
|
|
|
ZeroMemory(Sdis, sizeof(SIMPLEDIS));
|
|
|
|
pdis->CchFormatAddr((ADDR)Address, Sdis->szAddress, SD_STRINGMAX);
|
|
cb = (int)pdis->CbDisassemble((ADDR)Address, pb, cbMax);
|
|
|
|
if (cb == 0) {
|
|
|
|
//
|
|
// got an illegal op-code so just skip it
|
|
//
|
|
|
|
// get the smallest possible instruction size
|
|
cb = (pdis->Archt()==archtX86) ? 1 : 4;
|
|
|
|
//
|
|
// format the bytes and a phony opcode so the caller
|
|
// has something to print.
|
|
//
|
|
|
|
//
|
|
// ideally a new version of CchFormatBytes lets us do this:
|
|
// pdis->CchFormatBytes(Sdis->szRaw, SD_STRINGMAX, pb, cb);
|
|
// until then we have to make do with this:
|
|
//
|
|
|
|
for (int i = 0; i < cb; i++) {
|
|
_snprintf(Sdis->szRaw + 2*i, SD_STRINGMAX - 2*i, "%02X", (int)pb[i]);
|
|
}
|
|
|
|
_snprintf(Sdis->szOpcode, SD_STRINGMAX, "???");
|
|
|
|
//
|
|
// return a negative number so the caller knows how many bytes
|
|
// were consumed, but that there was not a valid instruction.
|
|
//
|
|
|
|
cb = -cb;
|
|
|
|
} else {
|
|
|
|
pdis->CchFormatBytes(Sdis->szRaw, SD_STRINGMAX);
|
|
pdis->CchFormatInstr(Sdis->szOpcode, SD_STRINGMAX);
|
|
|
|
if (Sdis->dwEA0 = pdis->AddrOperand(1)) {
|
|
pdis->CchFormatAddr(Sdis->dwEA0, Sdis->szEA0, SD_STRINGMAX);
|
|
fFoundEA = 1;
|
|
}
|
|
|
|
if (Sdis->dwEA1 = pdis->AddrOperand(2)) {
|
|
pdis->CchFormatAddr(Sdis->dwEA1, Sdis->szEA1, SD_STRINGMAX);
|
|
fFoundEA = 1;
|
|
}
|
|
|
|
if (Sdis->dwEA2 = pdis->AddrOperand(3)) {
|
|
pdis->CchFormatAddr(Sdis->dwEA2, Sdis->szEA2, SD_STRINGMAX);
|
|
fFoundEA = 1;
|
|
}
|
|
|
|
switch(pdis->Memreft()) {
|
|
case DIS::memreftNone:
|
|
case DIS::memreftOther:
|
|
Sdis->cbMemref = 0;
|
|
break;
|
|
|
|
default:
|
|
Sdis->cbMemref = pdis->CbMemoryReference();
|
|
break;
|
|
}
|
|
|
|
// branch stuff
|
|
trmt = pdis->Trmt();
|
|
|
|
switch (trmt) {
|
|
|
|
case trmtUnknown: // Block hasn't been analyzed
|
|
case trmtFallThrough: // 1 Fall into following block
|
|
break;
|
|
|
|
case trmtTrap: // 1 Trap, Unconditional
|
|
case trmtTrapCc: // 1 Trap, Conditional
|
|
Sdis->IsTrap = 1;
|
|
break;
|
|
|
|
|
|
case trmtBra: // 1 Branch, Unconditional, Direct
|
|
case trmtBraCc: // 2 Branch, Conditional, Direct
|
|
case trmtBraDef: // 1 Branch, Unconditional, Direct, Deferred
|
|
case trmtBraCcDef: // 2 Branch, Conditional, Direct, Deferred
|
|
Sdis->dwBranchTarget = pdis->AddrTarget();
|
|
Sdis->IsBranch = 1;
|
|
break;
|
|
|
|
|
|
|
|
case trmtBraCcInd: // 1 Branch, Conditional, Indirect
|
|
case trmtBraInd: // 0 Branch, Unconditional, Indirect
|
|
case trmtBraIndDef: // 0 Branch, Unconditional, Indirect, Deferred
|
|
case trmtBraCcIndDef: // 1 Branch, Conditional, Indirect, Deferred
|
|
Sdis->dwBranchTarget = pdis->AddrTarget();
|
|
Sdis->dwJumpTable = pdis->AddrJumpTable();
|
|
Sdis->cbJumpEntry = pdis->CbJumpEntry();
|
|
Sdis->IsBranch = 1;
|
|
break;
|
|
|
|
case trmtCallInd: // 1 Call, Unconditional, Indirect
|
|
case trmtCallIndDef: // 1 Call, Unconditional, Indirect, Deferred
|
|
|
|
case trmtCall: // 2 Call, Unconditional, Direct
|
|
case trmtCallCc: // 2 Call, Conditional, Direct
|
|
case trmtCallDef: // 2 Call, Unconditional, Direct, Deferred
|
|
case trmtCallCcDef: // 2 Call, Conditional, Direct, Deferred
|
|
|
|
Sdis->IsCall = 1;
|
|
break;
|
|
|
|
#if 0
|
|
#ifdef CASEJUMP
|
|
case trmtBraCase: // Switch/Case trmt
|
|
#endif
|
|
#ifdef AFTERCATCH
|
|
case trmtAfterCatch: // Code after catch block
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&CsEverything);
|
|
|
|
return cb;
|
|
}
|