390 lines
8.3 KiB
C++
390 lines
8.3 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// Functions dealing with instructions, such as assembly or disassembly.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997-2001.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
static ULONG64 s_igrepSearchStartAddress = 0L;
|
|
static ULONG64 s_igrepLastPc;
|
|
static CHAR s_igrepLastPattern[256];
|
|
|
|
ULONG g_AsmOptions;
|
|
|
|
// This array must be in ASMOPT bit order.
|
|
PCSTR g_AsmOptionNames[] =
|
|
{
|
|
"verbose"
|
|
};
|
|
|
|
void ChangeAsmOptions(BOOL Set, PSTR Args)
|
|
{
|
|
ULONG Flags = 0;
|
|
PSTR Arg;
|
|
ULONG i;
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// Parse out a single flag argument.
|
|
//
|
|
|
|
while (isspace(*Args))
|
|
{
|
|
*Args++;
|
|
}
|
|
if (*Args == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Arg = Args;
|
|
|
|
while (*Args && !isspace(*Args))
|
|
{
|
|
Args++;
|
|
}
|
|
if (isspace(*Args))
|
|
{
|
|
*Args++ = 0;
|
|
}
|
|
|
|
//
|
|
// Find value for argument.
|
|
//
|
|
|
|
for (i = 0; i < DIMA(g_AsmOptionNames); i++)
|
|
{
|
|
if (!_stricmp(Arg, g_AsmOptionNames[i]))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i < DIMA(g_AsmOptionNames))
|
|
{
|
|
Flags |= 1 << i;
|
|
}
|
|
else
|
|
{
|
|
ErrOut("Unknown assembly option '%s'\n", Arg);
|
|
}
|
|
}
|
|
|
|
if (Set)
|
|
{
|
|
g_AsmOptions |= Flags;
|
|
}
|
|
else
|
|
{
|
|
g_AsmOptions &= ~Flags;
|
|
}
|
|
|
|
dprintf("Assembly options:");
|
|
if (g_AsmOptions == 0)
|
|
{
|
|
dprintf(" <default>\n");
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < DIMA(g_AsmOptionNames); i++)
|
|
{
|
|
if (g_AsmOptions & (1 << i))
|
|
{
|
|
dprintf(" %s", g_AsmOptionNames[i]);
|
|
}
|
|
}
|
|
dprintf("\n");
|
|
}
|
|
}
|
|
|
|
void igrep (void)
|
|
{
|
|
ULONG64 dwNextGrepAddr;
|
|
ULONG64 dwCurrGrepAddr;
|
|
CHAR SourceLine[MAX_DISASM_LEN];
|
|
BOOL NewPc;
|
|
ULONG64 d;
|
|
PCHAR pc = g_CurCmd;
|
|
PCHAR Pattern;
|
|
PCHAR Expression;
|
|
CHAR Symbol[MAX_SYMBOL_LEN];
|
|
ULONG64 Displacement;
|
|
ADDR TempAddr;
|
|
ULONG64 dwCurrentPc;
|
|
|
|
g_Machine->GetPC(&TempAddr);
|
|
dwCurrentPc = Flat(TempAddr);
|
|
if ( s_igrepLastPc && s_igrepLastPc == dwCurrentPc )
|
|
{
|
|
NewPc = FALSE;
|
|
}
|
|
else
|
|
{
|
|
s_igrepLastPc = dwCurrentPc;
|
|
NewPc = TRUE;
|
|
}
|
|
|
|
//
|
|
// check for pattern.
|
|
//
|
|
|
|
Pattern = NULL;
|
|
Expression = NULL;
|
|
if (*pc)
|
|
{
|
|
while (*pc <= ' ')
|
|
{
|
|
pc++;
|
|
}
|
|
Pattern = pc;
|
|
while (*pc > ' ')
|
|
{
|
|
pc++;
|
|
}
|
|
|
|
//
|
|
// check for an expression
|
|
//
|
|
|
|
if (*pc != '\0')
|
|
{
|
|
*pc = '\0';
|
|
pc++;
|
|
if (*pc <= ' ')
|
|
{
|
|
while (*pc <= ' ')
|
|
{
|
|
pc++;
|
|
}
|
|
}
|
|
if (*pc)
|
|
{
|
|
Expression = pc;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Pattern)
|
|
{
|
|
for (pc = Pattern; *pc; pc++)
|
|
{
|
|
*pc = (CHAR)toupper(*pc);
|
|
}
|
|
s_igrepLastPattern[0] = '*';
|
|
strcpy(s_igrepLastPattern + 1, Pattern);
|
|
if (Pattern[0] == '*')
|
|
{
|
|
strcpy(s_igrepLastPattern, Pattern);
|
|
}
|
|
if (Pattern[strlen(Pattern)] != '*')
|
|
{
|
|
strcat(s_igrepLastPattern, "*");
|
|
}
|
|
}
|
|
|
|
if (Expression)
|
|
{
|
|
s_igrepSearchStartAddress = ExtGetExpression(Expression);
|
|
}
|
|
if (!s_igrepSearchStartAddress)
|
|
{
|
|
dprintf("Search address set to %s\n", FormatAddr64(s_igrepLastPc));
|
|
s_igrepSearchStartAddress = s_igrepLastPc;
|
|
return;
|
|
}
|
|
|
|
dwNextGrepAddr = s_igrepSearchStartAddress;
|
|
dwCurrGrepAddr = dwNextGrepAddr;
|
|
|
|
d = ExtDisasm(&dwNextGrepAddr, SourceLine, FALSE);
|
|
while (d)
|
|
{
|
|
for (pc = SourceLine; *pc; pc++)
|
|
{
|
|
*pc = (CHAR)tolower(*pc);
|
|
}
|
|
if (MatchPattern(SourceLine, s_igrepLastPattern))
|
|
{
|
|
g_LastExpressionValue = dwCurrGrepAddr;
|
|
s_igrepSearchStartAddress = dwNextGrepAddr;
|
|
GetSymbolStdCall(dwCurrGrepAddr, Symbol, sizeof(Symbol),
|
|
&Displacement, NULL);
|
|
ExtDisasm(&dwCurrGrepAddr, SourceLine, FALSE);
|
|
dprintf("%s", SourceLine);
|
|
return;
|
|
}
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
return;
|
|
}
|
|
|
|
dwCurrGrepAddr = dwNextGrepAddr;
|
|
d = ExtDisasm(&dwNextGrepAddr, SourceLine, FALSE);
|
|
}
|
|
}
|
|
|
|
/*** fnAssemble - interactive assembly routine
|
|
*
|
|
* Purpose:
|
|
* Function of "a <range>" command.
|
|
*
|
|
* Prompt the user with successive assembly addresses until
|
|
* a blank line is input. Assembly errors do not abort the
|
|
* function, but the prompt is output again for a retry.
|
|
* The variables g_CommandStart, g_CurCmd, and cbPrompt
|
|
* are set to make a local error context and restored on routine
|
|
* exit.
|
|
*
|
|
* Input:
|
|
* *addr - starting address for assembly
|
|
*
|
|
* Output:
|
|
* *addr - address after the last assembled instruction.
|
|
*
|
|
* Notes:
|
|
* all error processing is local, no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
TryAssemble(PADDR paddr)
|
|
{
|
|
char Assemble[MAX_DISASM_LEN];
|
|
|
|
//
|
|
// Set local prompt and command.
|
|
//
|
|
|
|
g_CommandStart = Assemble;
|
|
g_CurCmd = Assemble;
|
|
g_PromptLength = 9;
|
|
|
|
Assemble[0] = '\0';
|
|
|
|
while (TRUE)
|
|
{
|
|
char ch;
|
|
|
|
dprintAddr(paddr);
|
|
GetInput("", Assemble, sizeof(Assemble));
|
|
g_CurCmd = Assemble;
|
|
RemoveDelChar(g_CurCmd);
|
|
do
|
|
{
|
|
ch = *g_CurCmd++;
|
|
}
|
|
while (ch == ' ' || ch == '\t');
|
|
if (ch == '\0')
|
|
{
|
|
break;
|
|
}
|
|
g_CurCmd--;
|
|
|
|
assert(fFlat(*paddr) || fInstrPtr(*paddr));
|
|
g_Machine->Assemble(paddr, g_CurCmd);
|
|
}
|
|
}
|
|
|
|
void
|
|
fnAssemble(PADDR paddr)
|
|
{
|
|
//
|
|
// Save present prompt and command.
|
|
//
|
|
|
|
PSTR StartSave = g_CommandStart; // saved start of cmd buffer
|
|
PSTR CommandSave = g_CurCmd; // current ptr in cmd buffer
|
|
ULONG PromptSave = g_PromptLength; // size of prompt string
|
|
BOOL Done = FALSE;
|
|
|
|
while (!Done)
|
|
{
|
|
__try
|
|
{
|
|
TryAssemble(paddr);
|
|
|
|
// If assembly returned normally we're done.
|
|
Done = TRUE;
|
|
}
|
|
__except(CommandExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
// If illegal input was encountered keep looping.
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore entry prompt and command.
|
|
//
|
|
|
|
g_CommandStart = StartSave;
|
|
g_CurCmd = CommandSave;
|
|
g_PromptLength = PromptSave;
|
|
}
|
|
|
|
/*** fnUnassemble - disassembly of an address range
|
|
*
|
|
* Purpose:
|
|
* Function of "u<range>" command.
|
|
*
|
|
* Output the disassembly of the instruction in the given
|
|
* address range. Since some processors have variable
|
|
* instruction lengths, use fLength value to determine if
|
|
* instruction count or inclusive range should be used.
|
|
*
|
|
* Input:
|
|
* *addr - pointer to starting address to disassemble
|
|
* value - if fLength = TRUE, count of instructions to output
|
|
* if fLength = FALSE, ending address of inclusive range
|
|
*
|
|
* Output:
|
|
* *addr - address after last instruction disassembled
|
|
*
|
|
* Exceptions:
|
|
* error exit: MEMORY - memory access error
|
|
*
|
|
* Notes:
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
fnUnassemble (
|
|
PADDR Addr,
|
|
ULONG64 Value,
|
|
BOOL Length
|
|
)
|
|
{
|
|
if (!IS_MACHINE_ACCESSIBLE())
|
|
{
|
|
error(BADTHREAD);
|
|
}
|
|
|
|
CHAR Buffer[MAX_DISASM_LEN];
|
|
BOOL Status;
|
|
ADDR EndAddr;
|
|
ULONG SymAddrFlags = SYMADDR_FORCE | SYMADDR_LABEL | SYMADDR_SOURCE;
|
|
|
|
Flat(EndAddr) = Value;
|
|
|
|
while ((Length && Value--) || (!Length && AddrLt(*Addr, EndAddr)))
|
|
{
|
|
OutputSymAddr(Flat(*Addr), SymAddrFlags);
|
|
Status = g_Machine->Disassemble(Addr, Buffer, FALSE);
|
|
dprintf("%s", Buffer);
|
|
if (!Status)
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
|
|
SymAddrFlags &= ~SYMADDR_FORCE;
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|