2303 lines
49 KiB
C++
2303 lines
49 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// Functions dealing with memory access, such as reading, writing,
|
|
// dumping and entering.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997-2001.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
ULONG64 EXPRLastDump = 0L;
|
|
|
|
ADDR g_DumpDefault; // default dump address
|
|
|
|
/*** GetProcessMemString - get memory string values
|
|
*
|
|
* Purpose:
|
|
* To read a string of a specified length with the memory
|
|
* values selected. Break reads across page boundaries -
|
|
* multiples of the page size.
|
|
*
|
|
* Input:
|
|
* Addr - offset of memory to start reading
|
|
* Value - pointer to byte string to set with memory values
|
|
*
|
|
* Output:
|
|
* bytes at Value set if read successful
|
|
*
|
|
* Returns:
|
|
* number of bytes actually read
|
|
*
|
|
*************************************************************************/
|
|
|
|
ULONG
|
|
GetProcessMemString (
|
|
PPROCESS_INFO Process,
|
|
PADDR Addr,
|
|
PVOID Value,
|
|
ULONG Length
|
|
)
|
|
|
|
{
|
|
ULONG cTotalBytesRead = 0;
|
|
|
|
if (fFlat(*Addr) || fInstrPtr(*Addr))
|
|
{
|
|
PPROCESS_INFO OldCur = g_CurrentProcess;
|
|
g_CurrentProcess = Process;
|
|
|
|
if (g_Target->ReadVirtual(Flat(*Addr), Value, Length,
|
|
&cTotalBytesRead) != S_OK)
|
|
{
|
|
cTotalBytesRead = 0;
|
|
}
|
|
|
|
g_CurrentProcess = OldCur;
|
|
}
|
|
|
|
return cTotalBytesRead;
|
|
}
|
|
|
|
/*** SetProcessMemString - set memory string values
|
|
*
|
|
* Purpose:
|
|
* To write a string of a specified length with the memory
|
|
* values selected.
|
|
*
|
|
* Input:
|
|
* Addr - offset of memory to start writing
|
|
* Value - pointer to byte string to set with memory values
|
|
*
|
|
* Output:
|
|
* bytes at Value set if write successful
|
|
*
|
|
* Returns:
|
|
* number of bytes actually write
|
|
*
|
|
*************************************************************************/
|
|
|
|
ULONG
|
|
SetProcessMemString (
|
|
PPROCESS_INFO Process,
|
|
PADDR Addr,
|
|
PVOID Value,
|
|
ULONG Length
|
|
)
|
|
|
|
{
|
|
ULONG cTotalBytesWritten = 0;
|
|
|
|
if (fFlat(*Addr) || fInstrPtr(*Addr))
|
|
{
|
|
PPROCESS_INFO OldCur = g_CurrentProcess;
|
|
g_CurrentProcess = Process;
|
|
|
|
if (g_Target->WriteVirtual(Flat(*Addr), Value, Length,
|
|
&cTotalBytesWritten) != S_OK)
|
|
{
|
|
cTotalBytesWritten = 0;
|
|
}
|
|
|
|
g_CurrentProcess = OldCur;
|
|
}
|
|
|
|
return cTotalBytesWritten;
|
|
}
|
|
|
|
BOOL
|
|
CALLBACK
|
|
LocalSymbolEnumerator(
|
|
PSYMBOL_INFO pSymInfo,
|
|
ULONG Size,
|
|
PVOID Context
|
|
)
|
|
{
|
|
ULONG64 Value = pSymInfo->Register, Address = pSymInfo->Address;
|
|
|
|
TranslateAddress(pSymInfo->Flags, pSymInfo->Register, &Address, &Value);
|
|
|
|
VerbOut("%s ", FormatAddr64(Address));
|
|
dprintf("%15s = ", pSymInfo->Name);
|
|
if (pSymInfo->Flags & SYMF_REGISTER)
|
|
{
|
|
dprintf( "%I64x\n",
|
|
Value
|
|
);
|
|
}
|
|
else
|
|
{
|
|
if (!DumpSingleValue(pSymInfo))
|
|
{
|
|
dprintf("??");
|
|
}
|
|
dprintf("\n");
|
|
}
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// parseDumpCommand
|
|
//
|
|
// Parses memory dump commands.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
parseDumpCommand(
|
|
void
|
|
)
|
|
{
|
|
CHAR ch;
|
|
ULONG64 count;
|
|
ULONG size;
|
|
ULONG offset;
|
|
BOOL DumpSymbols;
|
|
|
|
static CHAR s_DumpPrimary = 'b';
|
|
static CHAR s_DumpSecondary = ' ';
|
|
|
|
ch = (CHAR)tolower(*g_CurCmd);
|
|
if (ch == 'a' || ch == 'b' || ch == 'c' || ch == 'd' ||
|
|
ch == 'f' || ch == 'g' || ch == 'l' || ch == 'u' ||
|
|
ch == 'w' || ch == 's' || ch == 'q' || ch == 't' ||
|
|
ch == 'v' || ch == 'y' || ch == 'p')
|
|
{
|
|
if (ch == 'd' || ch == 's')
|
|
{
|
|
s_DumpPrimary = *g_CurCmd;
|
|
}
|
|
else if (ch == 'p')
|
|
{
|
|
// 'p' maps to the effective pointer size dump.
|
|
s_DumpPrimary = g_Machine->m_Ptr64 ? 'q' : 'd';
|
|
}
|
|
else
|
|
{
|
|
s_DumpPrimary = ch;
|
|
}
|
|
|
|
g_CurCmd++;
|
|
|
|
s_DumpSecondary = ' ';
|
|
if (s_DumpPrimary == 'd' || s_DumpPrimary == 'q')
|
|
{
|
|
if (*g_CurCmd == 's')
|
|
{
|
|
s_DumpSecondary = *g_CurCmd++;
|
|
}
|
|
}
|
|
else if (s_DumpPrimary == 'l')
|
|
{
|
|
if (*g_CurCmd == 'b')
|
|
{
|
|
s_DumpSecondary = *g_CurCmd++;
|
|
}
|
|
}
|
|
else if (s_DumpPrimary == 'y')
|
|
{
|
|
if (*g_CurCmd == 'b' || *g_CurCmd == 'd')
|
|
{
|
|
s_DumpSecondary = *g_CurCmd++;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (s_DumpPrimary)
|
|
{
|
|
case 'a':
|
|
count = 384;
|
|
GetRange(&g_DumpDefault, &count, 1, SEGREG_DATA);
|
|
fnDumpAsciiMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
case 'b':
|
|
count = 128;
|
|
GetRange(&g_DumpDefault, &count, 1, SEGREG_DATA);
|
|
fnDumpByteMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
case 'c':
|
|
count = 32;
|
|
GetRange(&g_DumpDefault, &count, 4, SEGREG_DATA);
|
|
fnDumpDwordAndCharMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
case 'd':
|
|
count = 32;
|
|
DumpSymbols = s_DumpSecondary == 's';
|
|
GetRange(&g_DumpDefault, &count, 4, SEGREG_DATA);
|
|
fnDumpDwordMemory(&g_DumpDefault, (ULONG)count, DumpSymbols);
|
|
break;
|
|
|
|
case 'D':
|
|
count = 15;
|
|
GetRange(&g_DumpDefault, &count, 8, SEGREG_DATA);
|
|
fnDumpDoubleMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
case 'f':
|
|
count = 16;
|
|
GetRange(&g_DumpDefault, &count, 4, SEGREG_DATA);
|
|
fnDumpFloatMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
case 'g':
|
|
fnDumpSelector((ULONG)GetExpression());
|
|
break;
|
|
|
|
case 'l':
|
|
BOOL followBlink;
|
|
|
|
count = 32;
|
|
size = 4;
|
|
followBlink = s_DumpSecondary == 'b';
|
|
|
|
if ((ch = PeekChar()) != '\0' && ch != ';')
|
|
{
|
|
GetAddrExpression(SEGREG_DATA, &g_DumpDefault);
|
|
if ((ch = PeekChar()) != '\0' && ch != ';')
|
|
{
|
|
count = GetExpression();
|
|
if ((ch = PeekChar()) != '\0' && ch != ';')
|
|
{
|
|
size = (ULONG)GetExpression();
|
|
}
|
|
}
|
|
}
|
|
fnDumpListMemory(&g_DumpDefault, (ULONG)count, size, followBlink);
|
|
break;
|
|
|
|
case 'q':
|
|
count = 16;
|
|
DumpSymbols = s_DumpSecondary == 's';
|
|
GetRange(&g_DumpDefault, &count, 8, SEGREG_DATA);
|
|
fnDumpQuadMemory(&g_DumpDefault, (ULONG)count, DumpSymbols);
|
|
break;
|
|
|
|
case 's':
|
|
case 'S':
|
|
UNICODE_STRING64 UnicodeString;
|
|
ADDR BufferAddr;
|
|
|
|
count = 1;
|
|
GetRange(&g_DumpDefault, &count, 2, SEGREG_DATA);
|
|
while (count--)
|
|
{
|
|
if (g_Target->ReadUnicodeString(g_Machine, Flat(g_DumpDefault),
|
|
&UnicodeString) == S_OK)
|
|
{
|
|
ADDRFLAT(&BufferAddr, UnicodeString.Buffer);
|
|
if (s_DumpPrimary == 'S')
|
|
{
|
|
fnDumpUnicodeMemory( &BufferAddr,
|
|
UnicodeString.Length / sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
fnDumpAsciiMemory( &BufferAddr, UnicodeString.Length );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
case 'T':
|
|
SymbolTypeDumpEx(g_CurrentProcess->Handle,
|
|
g_CurrentProcess->ImageHead,
|
|
g_CurCmd);
|
|
break;
|
|
|
|
case 'u':
|
|
count = 384;
|
|
GetRange(&g_DumpDefault, &count, 2, SEGREG_DATA);
|
|
fnDumpUnicodeMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
case 'v':
|
|
RequireCurrentScope();
|
|
EnumerateLocals(LocalSymbolEnumerator, NULL);
|
|
break;
|
|
|
|
case 'w':
|
|
count = 64;
|
|
GetRange(&g_DumpDefault, &count, 2, SEGREG_DATA);
|
|
fnDumpWordMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
case 'y':
|
|
switch(s_DumpSecondary)
|
|
{
|
|
case 'b':
|
|
count = 32;
|
|
GetRange(&g_DumpDefault, &count, 1, SEGREG_DATA);
|
|
fnDumpByteBinaryMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
case 'd':
|
|
count = 8;
|
|
GetRange(&g_DumpDefault, &count, 4, SEGREG_DATA);
|
|
fnDumpDwordBinaryMemory(&g_DumpDefault, (ULONG)count);
|
|
break;
|
|
|
|
default:
|
|
error(SYNTAX);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
error(SYNTAX);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// DumpValues
|
|
//
|
|
// Generic columnar value dumper. Returns the number of values
|
|
// printed.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class DumpValues
|
|
{
|
|
public:
|
|
DumpValues(ULONG Size, ULONG Columns);
|
|
|
|
ULONG Dump(PADDR Start, ULONG Count);
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void) = 0;
|
|
virtual BOOL PrintValue(void) = 0;
|
|
virtual void PrintUnknown(void) = 0;
|
|
|
|
// Optional worker methods. Base implementations do nothing.
|
|
virtual void EndRow(void);
|
|
|
|
// Fixed members controlling how this instance dumps values.
|
|
ULONG m_Size;
|
|
ULONG m_Columns;
|
|
|
|
// Work members during dumping.
|
|
UCHAR* m_Value;
|
|
ULONG m_Col;
|
|
PADDR m_Start;
|
|
|
|
// Optional per-row values. Out is automatically reset to
|
|
// Base at the beginning of every row.
|
|
UCHAR* m_Base;
|
|
UCHAR* m_Out;
|
|
};
|
|
|
|
DumpValues::DumpValues(ULONG Size, ULONG Columns)
|
|
{
|
|
m_Size = Size;
|
|
m_Columns = Columns;
|
|
}
|
|
|
|
ULONG
|
|
DumpValues::Dump(PADDR Start, ULONG Count)
|
|
{
|
|
ULONG Read;
|
|
UCHAR ReadBuffer[512];
|
|
ULONG Idx;
|
|
ULONG Block;
|
|
BOOL First = TRUE;
|
|
ULONG64 Offset;
|
|
ULONG Printed;
|
|
BOOL RowStarted;
|
|
ULONG PageVal;
|
|
ULONG64 NextOffs, NextPage;
|
|
|
|
Offset = Flat(*Start);
|
|
Printed = 0;
|
|
RowStarted = FALSE;
|
|
m_Start = Start;
|
|
m_Col = 0;
|
|
m_Out = m_Base;
|
|
|
|
while (Count > 0)
|
|
{
|
|
Block = sizeof(ReadBuffer) / m_Size;
|
|
Block = min(Count, Block);
|
|
g_Target->NearestDifferentlyValidOffsets(Offset, &NextOffs, &NextPage);
|
|
PageVal = (ULONG)(NextPage - Offset + m_Size - 1) / m_Size;
|
|
Block = min(Block, PageVal);
|
|
|
|
Read = GetMemString(Start, ReadBuffer, Block * m_Size) / m_Size;
|
|
if (Read < Block && NextOffs < NextPage)
|
|
{
|
|
// In dump files data validity can change from
|
|
// one byte to the next so we cannot assume that
|
|
// stepping by pages will always be correct. Instead,
|
|
// if we didn't have a successful read we step just
|
|
// past the end of the valid data or to the next
|
|
// valid offset, whichever is farther.
|
|
if (Offset + (Read + 1) * m_Size < NextOffs)
|
|
{
|
|
Block = (ULONG)(NextOffs - Offset + m_Size - 1) / m_Size;
|
|
}
|
|
else
|
|
{
|
|
Block = Read + 1;
|
|
}
|
|
}
|
|
m_Value = ReadBuffer;
|
|
Idx = 0;
|
|
|
|
if (First && Read >= 1)
|
|
{
|
|
First = FALSE;
|
|
EXPRLastDump = GetValue();
|
|
}
|
|
|
|
while (Idx < Block)
|
|
{
|
|
while (m_Col < m_Columns && Idx < Block)
|
|
{
|
|
if (m_Col == 0)
|
|
{
|
|
dprintAddr(Start);
|
|
RowStarted = TRUE;
|
|
}
|
|
|
|
if (Idx < Read)
|
|
{
|
|
if (!PrintValue())
|
|
{
|
|
// Increment address since this value was
|
|
// examined, but do not increment print count
|
|
// or column since no output was produced.
|
|
AddrAdd(Start, m_Size);
|
|
goto Exit;
|
|
}
|
|
|
|
m_Value += m_Size;
|
|
}
|
|
else
|
|
{
|
|
PrintUnknown();
|
|
}
|
|
|
|
Idx++;
|
|
Printed++;
|
|
m_Col++;
|
|
AddrAdd(Start, m_Size);
|
|
}
|
|
|
|
if (m_Col == m_Columns)
|
|
{
|
|
EndRow();
|
|
m_Out = m_Base;
|
|
dprintf("\n");
|
|
RowStarted = FALSE;
|
|
m_Col = 0;
|
|
}
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
return Printed;
|
|
}
|
|
}
|
|
|
|
Count -= Block;
|
|
Offset += Block * m_Size;
|
|
}
|
|
|
|
Exit:
|
|
if (RowStarted)
|
|
{
|
|
EndRow();
|
|
m_Out = m_Base;
|
|
dprintf("\n");
|
|
}
|
|
|
|
return Printed;
|
|
}
|
|
|
|
void
|
|
DumpValues::EndRow(void)
|
|
{
|
|
// Empty base implementation.
|
|
}
|
|
|
|
/*** fnDumpAsciiMemory - output ascii strings from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "da<range>" command.
|
|
*
|
|
* Outputs the memory in the specified range as ascii
|
|
* strings up to 32 characters per line. The default
|
|
* display is 12 lines for 384 characters total.
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of characters to display as ascii
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "?",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpAscii : public DumpValues
|
|
{
|
|
public:
|
|
DumpAscii(void)
|
|
: DumpValues(sizeof(UCHAR), (sizeof(m_Buf) / sizeof(m_Buf[0]) - 1))
|
|
{
|
|
m_Base = m_Buf;
|
|
}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
virtual void EndRow(void);
|
|
|
|
UCHAR m_Buf[33];
|
|
};
|
|
|
|
ULONG64
|
|
DumpAscii::GetValue(void)
|
|
{
|
|
return *m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpAscii::PrintValue(void)
|
|
{
|
|
UCHAR ch;
|
|
|
|
ch = *m_Value;
|
|
if (ch == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (ch < 0x20 || ch > 0x7e)
|
|
{
|
|
ch = '.';
|
|
}
|
|
*m_Out++ = ch;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpAscii::PrintUnknown(void)
|
|
{
|
|
*m_Out++ = '?';
|
|
}
|
|
|
|
void
|
|
DumpAscii::EndRow(void)
|
|
{
|
|
*m_Out++ = 0;
|
|
dprintf(" \"%s\"", m_Base);
|
|
}
|
|
|
|
ULONG
|
|
fnDumpAsciiMemory(
|
|
PADDR Start,
|
|
ULONG Count
|
|
)
|
|
{
|
|
DumpAscii Dumper;
|
|
|
|
return Count - Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpUnicodeMemory - output unicode strings from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "du<range>" command.
|
|
*
|
|
* Outputs the memory in the specified range as unicode
|
|
* strings up to 32 characters per line. The default
|
|
* display is 12 lines for 384 characters total (768 bytes)
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of characters to display as ascii
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "?",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpUnicode : public DumpValues
|
|
{
|
|
public:
|
|
DumpUnicode(void)
|
|
: DumpValues(sizeof(WCHAR), (sizeof(m_Buf) / sizeof(m_Buf[0]) - 1))
|
|
{
|
|
m_Base = (PUCHAR)m_Buf;
|
|
}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
virtual void EndRow(void);
|
|
|
|
WCHAR m_Buf[33];
|
|
};
|
|
|
|
ULONG64
|
|
DumpUnicode::GetValue(void)
|
|
{
|
|
return *(WCHAR *)m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpUnicode::PrintValue(void)
|
|
{
|
|
WCHAR ch;
|
|
|
|
ch = *(WCHAR *)m_Value;
|
|
if (ch == UNICODE_NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (ch < 0x20 || ch > 0x7e)
|
|
{
|
|
ch = L'.';
|
|
}
|
|
*(WCHAR *)m_Out = ch;
|
|
m_Out += sizeof(WCHAR);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpUnicode::PrintUnknown(void)
|
|
{
|
|
*(WCHAR *)m_Out = L'?';
|
|
m_Out += sizeof(WCHAR);
|
|
}
|
|
|
|
void
|
|
DumpUnicode::EndRow(void)
|
|
{
|
|
*(WCHAR *)m_Out = UNICODE_NULL;
|
|
m_Out += sizeof(WCHAR);
|
|
dprintf(" \"%ws\"", m_Base);
|
|
}
|
|
|
|
ULONG
|
|
fnDumpUnicodeMemory(
|
|
PADDR Start,
|
|
ULONG Count
|
|
)
|
|
{
|
|
DumpUnicode Dumper;
|
|
|
|
return Count - Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpByteMemory - output byte values from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "db<range>" command.
|
|
*
|
|
* Output the memory in the specified range as hex
|
|
* byte values and ascii characters up to 16 bytes
|
|
* per line. The default display is 16 lines for
|
|
* 256 byte total.
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of bytes to display as hex and characters
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory location not accessible are output as "??" for
|
|
* byte values and "?" as characters, but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpByte : public DumpValues
|
|
{
|
|
public:
|
|
DumpByte(void)
|
|
: DumpValues(sizeof(UCHAR), (sizeof(m_Buf) / sizeof(m_Buf[0]) - 1))
|
|
{
|
|
m_Base = m_Buf;
|
|
}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
virtual void EndRow(void);
|
|
|
|
UCHAR m_Buf[17];
|
|
};
|
|
|
|
ULONG64
|
|
DumpByte::GetValue(void)
|
|
{
|
|
return *m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpByte::PrintValue(void)
|
|
{
|
|
UCHAR ch;
|
|
|
|
ch = *m_Value;
|
|
|
|
if (m_Col == 8)
|
|
{
|
|
dprintf("-");
|
|
}
|
|
else
|
|
{
|
|
dprintf(" ");
|
|
}
|
|
dprintf("%02x", ch);
|
|
|
|
if (ch < 0x20 || ch > 0x7e)
|
|
{
|
|
ch = '.';
|
|
}
|
|
*m_Out++ = ch;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpByte::PrintUnknown(void)
|
|
{
|
|
if (m_Col == 8)
|
|
{
|
|
dprintf("-??");
|
|
}
|
|
else
|
|
{
|
|
dprintf(" ??");
|
|
}
|
|
*m_Out++ = '?';
|
|
}
|
|
|
|
void
|
|
DumpByte::EndRow(void)
|
|
{
|
|
*m_Out++ = 0;
|
|
|
|
while (m_Col < m_Columns)
|
|
{
|
|
dprintf(" ");
|
|
m_Col++;
|
|
}
|
|
|
|
if ((m_Start->type & ADDR_1632) == ADDR_1632)
|
|
{
|
|
dprintf(" %s", m_Base);
|
|
}
|
|
else
|
|
{
|
|
dprintf(" %s", m_Base);
|
|
}
|
|
}
|
|
|
|
void
|
|
fnDumpByteMemory(
|
|
PADDR Start,
|
|
ULONG Count
|
|
)
|
|
{
|
|
DumpByte Dumper;
|
|
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpWordMemory - output word values from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "dw<range>" command.
|
|
*
|
|
* Output the memory in the specified range as word
|
|
* values up to 8 words per line. The default display
|
|
* is 16 lines for 128 words total.
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of words to be displayed
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "????",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpWord : public DumpValues
|
|
{
|
|
public:
|
|
DumpWord(void)
|
|
: DumpValues(sizeof(WORD), 8) {}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
};
|
|
|
|
ULONG64
|
|
DumpWord::GetValue(void)
|
|
{
|
|
return *(WORD *)m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpWord::PrintValue(void)
|
|
{
|
|
dprintf(" %04x", *(WORD *)m_Value);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpWord::PrintUnknown(void)
|
|
{
|
|
dprintf(" ????");
|
|
}
|
|
|
|
void
|
|
fnDumpWordMemory(
|
|
PADDR Start,
|
|
ULONG Count
|
|
)
|
|
{
|
|
DumpWord Dumper;
|
|
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpDwordMemory - output dword value from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "dd<range>" command.
|
|
*
|
|
* Output the memory in the specified range as double
|
|
* word values up to 4 double words per line. The default
|
|
* display is 16 lines for 64 double words total.
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of double words to be displayed
|
|
* fDumpSymbols - Dump symbol for DWORD.
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "????????",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpDword : public DumpValues
|
|
{
|
|
public:
|
|
DumpDword(BOOL DumpSymbols)
|
|
: DumpValues(sizeof(DWORD), DumpSymbols ? 1 : 4)
|
|
{
|
|
m_DumpSymbols = DumpSymbols;
|
|
}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
|
|
BOOL m_DumpSymbols;
|
|
};
|
|
|
|
ULONG64
|
|
DumpDword::GetValue(void)
|
|
{
|
|
return *(DWORD *)m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpDword::PrintValue(void)
|
|
{
|
|
CHAR SymBuf[MAX_SYMBOL_LEN];
|
|
USHORT StdCallArgs;
|
|
ULONG64 Displacement;
|
|
|
|
dprintf(" %08lx", *(DWORD *)m_Value);
|
|
|
|
if (m_DumpSymbols)
|
|
{
|
|
GetSymbolStdCall(EXTEND64(*(LONG *)m_Value),
|
|
SymBuf,
|
|
sizeof(SymBuf),
|
|
&Displacement,
|
|
&StdCallArgs);
|
|
|
|
if (*SymBuf)
|
|
{
|
|
dprintf(" %s", SymBuf);
|
|
if (Displacement)
|
|
{
|
|
dprintf("+0x%s", FormatDisp64(Displacement));
|
|
}
|
|
|
|
if (g_SymOptions & SYMOPT_LOAD_LINES)
|
|
{
|
|
OutputLineAddr(EXTEND64(*(LONG*)m_Value), " [%s @ %d]");
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpDword::PrintUnknown(void)
|
|
{
|
|
dprintf(" ????????");
|
|
}
|
|
|
|
void
|
|
fnDumpDwordMemory(
|
|
PADDR Start,
|
|
ULONG Count,
|
|
BOOL fDumpSymbols
|
|
)
|
|
{
|
|
DumpDword Dumper(fDumpSymbols);
|
|
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpDwordAndCharMemory - output dword value from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "dc<range>" command.
|
|
*
|
|
* Output the memory in the specified range as double
|
|
* word values up to 4 double words per line, followed by
|
|
* an ASCII character representation of the bytes.
|
|
* The default display is 16 lines for 64 double words total.
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of double words to be displayed
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "????????",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpDwordAndChar : public DumpValues
|
|
{
|
|
public:
|
|
DumpDwordAndChar(void)
|
|
: DumpValues(sizeof(DWORD), (sizeof(m_Buf) - 1) / sizeof(DWORD))
|
|
{
|
|
m_Base = m_Buf;
|
|
}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
virtual void EndRow(void);
|
|
|
|
UCHAR m_Buf[17];
|
|
};
|
|
|
|
ULONG64
|
|
DumpDwordAndChar::GetValue(void)
|
|
{
|
|
return *(DWORD *)m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpDwordAndChar::PrintValue(void)
|
|
{
|
|
UCHAR ch;
|
|
ULONG byte;
|
|
|
|
dprintf(" %08x", *(DWORD *)m_Value);
|
|
|
|
for (byte = 0; byte < sizeof(DWORD); byte++)
|
|
{
|
|
ch = *(m_Value + byte);
|
|
if (ch < 0x20 || ch > 0x7e)
|
|
{
|
|
ch = '.';
|
|
}
|
|
*m_Out++ = ch;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpDwordAndChar::PrintUnknown(void)
|
|
{
|
|
dprintf(" ????????");
|
|
*m_Out++ = '?';
|
|
*m_Out++ = '?';
|
|
*m_Out++ = '?';
|
|
*m_Out++ = '?';
|
|
}
|
|
|
|
void
|
|
DumpDwordAndChar::EndRow(void)
|
|
{
|
|
*m_Out++ = 0;
|
|
while (m_Col < m_Columns)
|
|
{
|
|
dprintf(" ");
|
|
m_Col++;
|
|
}
|
|
dprintf(" %s", m_Base);
|
|
}
|
|
|
|
void
|
|
fnDumpDwordAndCharMemory(PADDR Start, ULONG Count)
|
|
{
|
|
DumpDwordAndChar Dumper;
|
|
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpListMemory - output linked list from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "dl addr length size" command.
|
|
*
|
|
* Output the memory in the specified range as a linked list
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of list elements to be displayed
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "????????",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
fnDumpListMemory(
|
|
PADDR Start,
|
|
ULONG elemcount,
|
|
ULONG size,
|
|
BOOL followBlink
|
|
)
|
|
{
|
|
ULONG64 firstaddr;
|
|
ULONG64 link;
|
|
LIST_ENTRY64 list;
|
|
ADDR curaddr;
|
|
ULONG linkSize;
|
|
PULONG plink;
|
|
|
|
if (Type(*Start) & (ADDR_UNKNOWN | ADDR_V86 | ADDR_16 | ADDR_1632))
|
|
{
|
|
dprintf("[%u,%x:%x`%08x,%08x`%08x] - bogus address type.\n",
|
|
Type(*Start),
|
|
Start->seg,
|
|
(ULONG)(Off(*Start)>>32),
|
|
(ULONG)Off(*Start),
|
|
(ULONG)(Flat(*Start)>>32),
|
|
(ULONG)Flat(*Start)
|
|
);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Setup to follow forward or backward links. Avoid reading more
|
|
// than the forward link here if going forwards. (in case the link
|
|
// is at the end of a page).
|
|
//
|
|
|
|
firstaddr = Flat(*Start);
|
|
while (elemcount-- != 0 && Flat(*Start) != 0)
|
|
{
|
|
if (followBlink)
|
|
{
|
|
if (g_Target->ReadListEntry(g_Machine,
|
|
Flat(*Start), &list) != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
link = list.Blink;
|
|
}
|
|
else
|
|
{
|
|
if (g_Target->ReadPointer(g_Machine,
|
|
Flat(*Start), &link) != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
curaddr = *Start;
|
|
if (g_Machine->m_Ptr64)
|
|
{
|
|
fnDumpQuadMemory(&curaddr, size, FALSE);
|
|
}
|
|
else
|
|
{
|
|
fnDumpDwordMemory(&curaddr, size, FALSE);
|
|
}
|
|
|
|
//
|
|
// If we get back to the first entry, we're done.
|
|
//
|
|
|
|
if (link == firstaddr)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Bail if the link is immediately circular.
|
|
//
|
|
|
|
if (Flat(*Start) == link)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Flat(*Start) = Start->off = link;
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
WarnOut("-- User interrupt\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// fnDumpFloatMemory
|
|
//
|
|
// Dumps float values.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class DumpFloat : public DumpValues
|
|
{
|
|
public:
|
|
DumpFloat(void)
|
|
: DumpValues(sizeof(float), 4) {}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
};
|
|
|
|
ULONG64
|
|
DumpFloat::GetValue(void)
|
|
{
|
|
// NTRAID#72849-2000/02/09-drewb.
|
|
// Expression results are always integers right now
|
|
// so just return the raw bits for the float.
|
|
return *(ULONG *)m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpFloat::PrintValue(void)
|
|
{
|
|
dprintf(" %16.8g", *(float *)m_Value);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpFloat::PrintUnknown(void)
|
|
{
|
|
dprintf(" ????????????????");
|
|
}
|
|
|
|
void
|
|
fnDumpFloatMemory(PADDR Start, ULONG Count)
|
|
{
|
|
DumpFloat Dumper;
|
|
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// fnDumpDoubleMemory
|
|
//
|
|
// Dumps double values.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class DumpDouble : public DumpValues
|
|
{
|
|
public:
|
|
DumpDouble(void)
|
|
: DumpValues(sizeof(double), 3) {}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
};
|
|
|
|
ULONG64
|
|
DumpDouble::GetValue(void)
|
|
{
|
|
// NTRAID#72849-2000/02/09-drewb.
|
|
// Expression results are always integers right now
|
|
// so just return the raw bits for the float.
|
|
return *(ULONG64 *)m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpDouble::PrintValue(void)
|
|
{
|
|
dprintf(" %22.12lg", *(double *)m_Value);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpDouble::PrintUnknown(void)
|
|
{
|
|
dprintf(" ????????????????????????");
|
|
}
|
|
|
|
void
|
|
fnDumpDoubleMemory(PADDR Start, ULONG Count)
|
|
{
|
|
DumpDouble Dumper;
|
|
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpQuadMemory - output quad value from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "dq<range>" command.
|
|
*
|
|
* Output the memory in the specified range as quad
|
|
* word values up to 2 quad words per line. The default
|
|
* display is 16 lines for 32 quad words total.
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of double words to be displayed
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "????????",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpQuad : public DumpValues
|
|
{
|
|
public:
|
|
DumpQuad(BOOL DumpSymbols)
|
|
: DumpValues(sizeof(ULONGLONG), DumpSymbols ? 1 : 2)
|
|
{
|
|
m_DumpSymbols = DumpSymbols;
|
|
}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
|
|
BOOL m_DumpSymbols;
|
|
};
|
|
|
|
ULONG64
|
|
DumpQuad::GetValue(void)
|
|
{
|
|
return *(ULONG64 *)m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpQuad::PrintValue(void)
|
|
{
|
|
CHAR SymBuf[MAX_SYMBOL_LEN];
|
|
USHORT StdCallArgs;
|
|
ULONG64 Displacement;
|
|
|
|
ULONG64 Val = *(ULONG64*)m_Value;
|
|
dprintf(" %08lx`%08lx", (ULONG)(Val >> 32), (ULONG)Val);
|
|
|
|
if (m_DumpSymbols)
|
|
{
|
|
GetSymbolStdCall(Val,
|
|
SymBuf,
|
|
sizeof(SymBuf),
|
|
&Displacement,
|
|
&StdCallArgs);
|
|
|
|
if (*SymBuf)
|
|
{
|
|
dprintf(" %s", SymBuf);
|
|
if (Displacement)
|
|
{
|
|
dprintf("+0x%s", FormatDisp64(Displacement));
|
|
}
|
|
|
|
if (g_SymOptions & SYMOPT_LOAD_LINES)
|
|
{
|
|
OutputLineAddr(Val, " [%s @ %d]");
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpQuad::PrintUnknown(void)
|
|
{
|
|
dprintf(" ????????`????????");
|
|
}
|
|
|
|
void
|
|
fnDumpQuadMemory(
|
|
PADDR Start,
|
|
ULONG Count,
|
|
BOOL fDumpSymbols
|
|
)
|
|
{
|
|
DumpQuad Dumper(fDumpSymbols);
|
|
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpByteBinaryMemory - output binary value from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "dyb<range>" command.
|
|
*
|
|
* Output the memory in the specified range as binary
|
|
* values up to 32 bits per line. The default
|
|
* display is 8 lines for 32 bytes total.
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of double words to be displayed
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "????????",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpByteBinary : public DumpValues
|
|
{
|
|
public:
|
|
DumpByteBinary(void)
|
|
: DumpValues(sizeof(UCHAR), (DIMA(m_HexValue) - 1) / 3)
|
|
{
|
|
m_Base = m_HexValue;
|
|
}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
virtual void EndRow(void);
|
|
|
|
UCHAR m_HexValue[13];
|
|
};
|
|
|
|
ULONG64
|
|
DumpByteBinary::GetValue(void)
|
|
{
|
|
return *m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpByteBinary::PrintValue(void)
|
|
{
|
|
ULONG i;
|
|
UCHAR RawVal;
|
|
|
|
RawVal = *m_Value;
|
|
|
|
sprintf((PSTR)m_Out, " %02x", RawVal);
|
|
m_Out += 3;
|
|
|
|
dprintf(" ");
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
dprintf("%c", (RawVal & 0x80) ? '1' : '0');
|
|
RawVal <<= 1;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpByteBinary::PrintUnknown(void)
|
|
{
|
|
dprintf(" ????????");
|
|
strcpy((PSTR)m_Out, " ??");
|
|
m_Out += 3;
|
|
}
|
|
|
|
void
|
|
DumpByteBinary::EndRow(void)
|
|
{
|
|
while (m_Col < m_Columns)
|
|
{
|
|
dprintf(" ");
|
|
m_Col++;
|
|
}
|
|
dprintf(" %s", m_HexValue);
|
|
}
|
|
|
|
void
|
|
fnDumpByteBinaryMemory(
|
|
PADDR Start,
|
|
ULONG Count
|
|
)
|
|
{
|
|
DumpByteBinary Dumper;
|
|
PSTR Blanks = g_Machine->m_Ptr64 ? " " : " ";
|
|
|
|
dprintf("%s 76543210 76543210 76543210 76543210\n", Blanks);
|
|
dprintf("%s -------- -------- -------- --------\n", Blanks);
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
/*** fnDumpDwordBinaryMemory - output binary value from memory
|
|
*
|
|
* Purpose:
|
|
* Function of "dyd<range>" command.
|
|
*
|
|
* Output the memory in the specified range as binary
|
|
* values of 32 bits per line. The default
|
|
* display is 8 lines for 8 dwords total.
|
|
*
|
|
* Input:
|
|
* Start - starting address to begin display
|
|
* Count - number of double words to be displayed
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* memory locations not accessible are output as "????????",
|
|
* but no errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
class DumpDwordBinary : public DumpValues
|
|
{
|
|
public:
|
|
DumpDwordBinary(void)
|
|
: DumpValues(sizeof(ULONG), 1)
|
|
{
|
|
}
|
|
|
|
protected:
|
|
// Worker methods that derived classes must define.
|
|
virtual ULONG64 GetValue(void);
|
|
virtual BOOL PrintValue(void);
|
|
virtual void PrintUnknown(void);
|
|
virtual void EndRow(void);
|
|
|
|
UCHAR m_HexValue[9];
|
|
};
|
|
|
|
ULONG64
|
|
DumpDwordBinary::GetValue(void)
|
|
{
|
|
return *(PULONG)m_Value;
|
|
}
|
|
|
|
BOOL
|
|
DumpDwordBinary::PrintValue(void)
|
|
{
|
|
ULONG i;
|
|
ULONG RawVal;
|
|
|
|
RawVal = *(PULONG)m_Value;
|
|
|
|
sprintf((PSTR)m_HexValue, "%08lx", RawVal);
|
|
|
|
for (i = 0; i < sizeof(ULONG) * 8; i++)
|
|
{
|
|
if ((i & 7) == 0)
|
|
{
|
|
dprintf(" ");
|
|
}
|
|
|
|
dprintf("%c", (RawVal & 0x80000000) ? '1' : '0');
|
|
RawVal <<= 1;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
DumpDwordBinary::PrintUnknown(void)
|
|
{
|
|
dprintf(" ???????? ???????? ???????? ????????");
|
|
strcpy((PSTR)m_HexValue, "????????");
|
|
}
|
|
|
|
void
|
|
DumpDwordBinary::EndRow(void)
|
|
{
|
|
dprintf(" %s", m_HexValue);
|
|
}
|
|
|
|
void
|
|
fnDumpDwordBinaryMemory(
|
|
PADDR Start,
|
|
ULONG Count
|
|
)
|
|
{
|
|
DumpDwordBinary Dumper;
|
|
PSTR Blanks = g_Machine->m_Ptr64 ? " " : " ";
|
|
|
|
dprintf("%s 3 2 1 0\n", Blanks);
|
|
dprintf("%s 10987654 32109876 54321098 76543210\n", Blanks);
|
|
dprintf("%s -------- -------- -------- --------\n", Blanks);
|
|
Dumper.Dump(Start, Count);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// fnDumpSelector
|
|
//
|
|
// Dumps an x86 selector.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
fnDumpSelector(
|
|
ULONG Selector
|
|
)
|
|
{
|
|
DESCRIPTOR64 Desc;
|
|
ULONG Type;
|
|
LPSTR TypeName;
|
|
PSTR PreFill, PostFill, Dash;
|
|
|
|
if (g_Target->GetSelDescriptor(g_Machine,
|
|
g_CurrentProcess->CurrentThread->Handle,
|
|
Selector, &Desc) != S_OK)
|
|
{
|
|
ErrOut("Unable to get selector %X description\n", Selector);
|
|
return;
|
|
}
|
|
|
|
if (g_Machine->m_Ptr64)
|
|
{
|
|
PreFill = " ";
|
|
PostFill = " ";
|
|
Dash = "---------";
|
|
}
|
|
else
|
|
{
|
|
PreFill = "";
|
|
PostFill = "";
|
|
Dash = "";
|
|
}
|
|
|
|
dprintf("Selector %sBase%s %sLimit%s Type DPL Size Gran\n",
|
|
PreFill, PostFill, PreFill, PostFill);
|
|
dprintf("-------- --------%s --------%s ------ --- ------- ----\n",
|
|
Dash, Dash);
|
|
|
|
Type = X86_DESC_TYPE(Desc.Flags);
|
|
if ( Type & 0x10 )
|
|
{
|
|
if ( Type & 0x8 )
|
|
{
|
|
// Code Descriptor
|
|
TypeName = " Code ";
|
|
}
|
|
else
|
|
{
|
|
// Data Descriptor
|
|
TypeName = " Data ";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TypeName = " Sys. ";
|
|
}
|
|
|
|
// 1234 12345678 12345678 ?Type? 1 ....... ....
|
|
dprintf(" %04X %s %s %s %d %s %s\n",
|
|
Selector,
|
|
FormatAddr64(Desc.Base),
|
|
FormatAddr64(Desc.Limit),
|
|
TypeName,
|
|
X86_DESC_PRIVILEGE(Desc.Flags),
|
|
(Desc.Flags & X86_DESC_DEFAULT_BIG) ? " Big " : "Not Big",
|
|
(Desc.Flags & X86_DESC_GRANULARITY) ? "Page" : "Byte"
|
|
);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// parseEnterCommand
|
|
//
|
|
// Parses memory entry commands.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
parseEnterCommand(
|
|
void
|
|
)
|
|
{
|
|
CHAR ch;
|
|
static CHAR s_EnterType = 'b';
|
|
ADDR addr1;
|
|
UCHAR list[STRLISTSIZE * 2];
|
|
PUCHAR plist = &list[0];
|
|
ULONG count;
|
|
ULONG size;
|
|
|
|
ch = (CHAR)tolower(*g_CurCmd);
|
|
if (ch == 'a' || ch == 'b' || ch == 'w' || ch == 'd' || ch == 'q' ||
|
|
ch == 'u')
|
|
{
|
|
g_CurCmd++;
|
|
s_EnterType = ch;
|
|
}
|
|
GetAddrExpression(SEGREG_DATA, &addr1);
|
|
if (s_EnterType == 'a' || s_EnterType == 'u')
|
|
{
|
|
AsciiList((PSTR)list, &count);
|
|
if (count == 0)
|
|
{
|
|
error(UNIMPLEMENT); //TEMP
|
|
}
|
|
|
|
if (s_EnterType == 'u')
|
|
{
|
|
ULONG Ansi;
|
|
|
|
// Expand ANSI to Unicode.
|
|
Ansi = count;
|
|
count *= 2;
|
|
while (Ansi-- > 0)
|
|
{
|
|
list[Ansi * 2] = list[Ansi];
|
|
list[Ansi * 2 + 1] = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size = 1;
|
|
if (s_EnterType == 'w')
|
|
{
|
|
size = 2;
|
|
}
|
|
else if (s_EnterType == 'd')
|
|
{
|
|
size = 4;
|
|
}
|
|
else if (s_EnterType == 'q')
|
|
{
|
|
size = 8;
|
|
}
|
|
|
|
HexList(list, &count, size);
|
|
if (count == 0)
|
|
{
|
|
fnInteractiveEnterMemory(&addr1, size);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// memory was entered at the command line.
|
|
// just write it in, one byte at a time
|
|
//
|
|
|
|
while (count--)
|
|
{
|
|
if (SetMemString(&addr1, plist++, 1) != 1)
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
AddrAdd(&addr1, 1);
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
WarnOut("-- User interrupt\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// fnInteractiveEnterMemory
|
|
//
|
|
// Interactively walks through memory, displaying current contents
|
|
// and prompting for new contents.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void
|
|
fnInteractiveEnterMemory(
|
|
PADDR Address,
|
|
ULONG Size
|
|
)
|
|
{
|
|
CHAR EnterBuf[1024];
|
|
PSTR Enter;
|
|
ULONG64 Content;
|
|
PSTR CmdSaved = g_CurCmd;
|
|
PSTR StartSaved = g_CommandStart;
|
|
ULONG64 EnteredValue;
|
|
CHAR ch;
|
|
|
|
g_PromptLength = 9 + 2 * Size;
|
|
|
|
while (TRUE)
|
|
{
|
|
if (GetMemString(Address, (PUCHAR)&Content, Size) != Size)
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
dprintAddr(Address);
|
|
|
|
switch (Size)
|
|
{
|
|
case 1:
|
|
dprintf("%02x", (UCHAR)Content);
|
|
break;
|
|
|
|
case 2:
|
|
dprintf("%04x", (USHORT)Content);
|
|
break;
|
|
|
|
case 4:
|
|
dprintf("%08lx", (ULONG)Content);
|
|
break;
|
|
|
|
case 8:
|
|
dprintf("%08lx`%08lx", (ULONG)(Content>>32), (ULONG)Content);
|
|
break;
|
|
}
|
|
|
|
GetInput(" ", EnterBuf, 1024);
|
|
RemoveDelChar(EnterBuf);
|
|
Enter = EnterBuf;
|
|
|
|
if (*Enter == '\0')
|
|
{
|
|
g_CurCmd = CmdSaved;
|
|
g_CommandStart = StartSaved;
|
|
return;
|
|
}
|
|
|
|
ch = *Enter;
|
|
while (ch == ' ' || ch == '\t' || ch == ';')
|
|
{
|
|
ch = *++Enter;
|
|
}
|
|
|
|
if (*Enter == '\0')
|
|
{
|
|
AddrAdd(Address, Size);
|
|
continue;
|
|
}
|
|
|
|
g_CurCmd = Enter;
|
|
g_CommandStart = Enter;
|
|
EnteredValue = HexValue(Size);
|
|
|
|
if (SetMemString(Address, (PUCHAR)&EnteredValue, Size) != Size)
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
AddrAdd(Address, Size);
|
|
}
|
|
}
|
|
|
|
/*** fnCompareMemory - compare two ranges of memory
|
|
*
|
|
* Purpose:
|
|
* Function of "c<range><addr>" command.
|
|
*
|
|
* To compare two ranges of memory, starting at offsets
|
|
* src1addr and src2addr, respectively, for length bytes.
|
|
* Bytes that mismatch are displayed with their offsets
|
|
* and contents.
|
|
*
|
|
* Input:
|
|
* src1addr - start of first memory region
|
|
* length - count of bytes to compare
|
|
* src2addr - start of second memory region
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Exceptions:
|
|
* error exit: MEMORY - memory read access failure
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
fnCompareMemory(
|
|
PADDR src1addr,
|
|
ULONG length,
|
|
PADDR src2addr
|
|
)
|
|
{
|
|
ULONG compindex;
|
|
UCHAR src1ch;
|
|
UCHAR src2ch;
|
|
|
|
for (compindex = 0; compindex < length; compindex++)
|
|
{
|
|
if (!GetMemByte(src1addr, &src1ch))
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
if (!GetMemByte(src2addr, &src2ch))
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
if (src1ch != src2ch)
|
|
{
|
|
dprintAddr(src1addr); dprintf(" %02x - ", src1ch);
|
|
dprintAddr(src2addr); dprintf(" %02x\n", src2ch);
|
|
}
|
|
AddrAdd(src1addr,1);
|
|
AddrAdd(src2addr,1);
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
WarnOut("-- User interrupt\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*** fnMoveMemory - move a range of memory to another
|
|
*
|
|
* Purpose:
|
|
* Function of "m<range><addr>" command.
|
|
*
|
|
* To move a range of memory starting at srcaddr to memory
|
|
* starting at destaddr for length bytes.
|
|
*
|
|
* Input:
|
|
* srcaddr - start of source memory region
|
|
* length - count of bytes to move
|
|
* destaddr - start of destination memory region
|
|
*
|
|
* Output:
|
|
* memory at destaddr has moved values
|
|
*
|
|
* Exceptions:
|
|
* error exit: MEMORY - memory reading or writing access failure
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
fnMoveMemory(
|
|
PADDR srcaddr,
|
|
ULONG length,
|
|
PADDR destaddr
|
|
)
|
|
{
|
|
UCHAR ch;
|
|
ULONG64 incr = 1;
|
|
|
|
if (AddrLt(*srcaddr, *destaddr))
|
|
{
|
|
AddrAdd(srcaddr, length - 1);
|
|
AddrAdd(destaddr, length - 1);
|
|
incr = (ULONG64)-1;
|
|
}
|
|
while (length--)
|
|
{
|
|
if (GetMemString(srcaddr, &ch, 1) != 1)
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
if (SetMemString(destaddr, &ch, 1) != 1)
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
AddrAdd(srcaddr, incr);
|
|
AddrAdd(destaddr, incr);
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
WarnOut("-- User interrupt\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*** fnFillMemory - fill memory with a byte list
|
|
*
|
|
* Purpose:
|
|
* Function of "f<range><bytelist>" command.
|
|
*
|
|
* To fill a range of memory with the byte list specified.
|
|
* The pattern repeats if the range size is larger than the
|
|
* byte list size.
|
|
*
|
|
* Input:
|
|
* Start - offset of memory to fill
|
|
* length - number of bytes to fill
|
|
* *plist - pointer to byte array to define values to set
|
|
* length - size of *plist array
|
|
*
|
|
* Exceptions:
|
|
* error exit: MEMORY - memory write access failure
|
|
*
|
|
* Output:
|
|
* memory at Start filled.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
ParseFillMemory(void)
|
|
{
|
|
HRESULT Status;
|
|
BOOL Virtual = TRUE;
|
|
ADDR Addr;
|
|
ULONG64 Size;
|
|
UCHAR Pattern[STRLISTSIZE];
|
|
ULONG PatternSize;
|
|
ULONG Done;
|
|
|
|
if (*g_CurCmd == 'p')
|
|
{
|
|
Virtual = FALSE;
|
|
g_CurCmd++;
|
|
}
|
|
|
|
GetRange(&Addr, &Size, 1, SEGREG_DATA);
|
|
HexList(Pattern, &PatternSize, 1);
|
|
if (PatternSize == 0)
|
|
{
|
|
error(SYNTAX);
|
|
}
|
|
|
|
if (Virtual)
|
|
{
|
|
Status = g_Target->FillVirtual(Flat(Addr), (ULONG)Size,
|
|
Pattern, PatternSize,
|
|
&Done);
|
|
}
|
|
else
|
|
{
|
|
Status = g_Target->FillPhysical(Flat(Addr), (ULONG)Size,
|
|
Pattern, PatternSize,
|
|
&Done);
|
|
}
|
|
|
|
if (Status != S_OK)
|
|
{
|
|
error(MEMORY);
|
|
}
|
|
else
|
|
{
|
|
dprintf("Filled 0x%x bytes\n", Done);
|
|
}
|
|
}
|
|
|
|
/*** fnSearchMemory - search memory with for a byte list
|
|
*
|
|
* Purpose:
|
|
* Function of "s<range><bytelist>" command.
|
|
*
|
|
* To search a range of memory with the byte list specified.
|
|
* If a match occurs, the offset of memory is output.
|
|
*
|
|
* Input:
|
|
* Start - offset of memory to start search
|
|
* length - size of range to search
|
|
* *plist - pointer to byte array to define values to search
|
|
* count - size of *plist array
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Exceptions:
|
|
* error exit: MEMORY - memory read access failure
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
fnSearchMemory(
|
|
PADDR Start,
|
|
ULONG64 length,
|
|
PUCHAR plist,
|
|
ULONG count,
|
|
ULONG Granularity
|
|
)
|
|
{
|
|
ULONG searchindex;
|
|
ULONG listindex;
|
|
UCHAR ch;
|
|
ADDR tAddr = *Start;
|
|
|
|
ULONG64 Found;
|
|
LONG64 SearchLength = length;
|
|
HRESULT st;
|
|
|
|
do
|
|
{
|
|
st = g_Target->SearchVirtual(Flat(*Start),
|
|
SearchLength,
|
|
plist,
|
|
count,
|
|
Granularity,
|
|
&Found);
|
|
if (st == S_OK)
|
|
{
|
|
ADDRFLAT(&tAddr, Found);
|
|
switch(Granularity)
|
|
{
|
|
case 1:
|
|
fnDumpByteMemory(&tAddr, 16);
|
|
break;
|
|
case 2:
|
|
fnDumpWordMemory(&tAddr, 8);
|
|
break;
|
|
case 4:
|
|
fnDumpDwordAndCharMemory(&tAddr, 4);
|
|
break;
|
|
case 8:
|
|
fnDumpQuadMemory(&tAddr, 2, FALSE);
|
|
break;
|
|
}
|
|
|
|
// Flush out the output immediately so that
|
|
// the user can see partial results during long searches.
|
|
FlushCallbacks();
|
|
|
|
SearchLength -= Found - Flat(*Start) + Granularity;
|
|
AddrAdd(Start, (ULONG)(Found - Flat(*Start) + Granularity));
|
|
|
|
if (CheckUserInterrupt())
|
|
{
|
|
WarnOut("-- User interrupt\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
while (SearchLength > 0 && st == S_OK);
|
|
}
|
|
|
|
void
|
|
ParseSearchMemory(void)
|
|
{
|
|
ADDR Addr;
|
|
ULONG64 Length;
|
|
UCHAR Pat[STRLISTSIZE];
|
|
ULONG PatLen;
|
|
ULONG Gran;
|
|
|
|
while (*g_CurCmd == ' ')
|
|
{
|
|
g_CurCmd++;
|
|
}
|
|
|
|
Gran = 1;
|
|
|
|
if (*g_CurCmd == '-')
|
|
{
|
|
g_CurCmd++;
|
|
switch(*g_CurCmd)
|
|
{
|
|
case 'w':
|
|
Gran = 2;
|
|
break;
|
|
case 'd':
|
|
Gran = 4;
|
|
break;
|
|
case 'q':
|
|
Gran = 8;
|
|
break;
|
|
default:
|
|
error(SYNTAX);
|
|
break;
|
|
}
|
|
g_CurCmd++;
|
|
}
|
|
|
|
ADDRFLAT(&Addr, 0);
|
|
Length = 16;
|
|
GetRange(&Addr, &Length, Gran, SEGREG_DATA);
|
|
if (Flat(Addr))
|
|
{
|
|
HexList(Pat, &PatLen, Gran);
|
|
if (PatLen == 0)
|
|
{
|
|
PCSTR Err = "Search pattern missing from";
|
|
ReportError(SYNTAX, &Err);
|
|
}
|
|
|
|
fnSearchMemory(&Addr, Length * Gran, Pat, PatLen, Gran);
|
|
}
|
|
}
|
|
|
|
/*** fnInputIo - read and output io
|
|
*
|
|
* Purpose:
|
|
* Function of "ib, iw, id <address>" command.
|
|
*
|
|
* Read (input) and print the value at the specified io address.
|
|
*
|
|
* Input:
|
|
* IoAddress - Address to read.
|
|
* InputType - The size type 'b', 'w', or 'd'
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* I/O locations not accessible are output as "??", "????", or
|
|
* "????????", depending on size. No errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
fnInputIo(
|
|
ULONG64 IoAddress,
|
|
UCHAR InputType
|
|
)
|
|
{
|
|
ULONG InputValue;
|
|
ULONG InputSize = 1;
|
|
HRESULT Status;
|
|
CHAR Format[] = "%01lx";
|
|
|
|
InputValue = 0;
|
|
|
|
if (InputType == 'w')
|
|
{
|
|
InputSize = 2;
|
|
}
|
|
else if (InputType == 'd')
|
|
{
|
|
InputSize = 4;
|
|
}
|
|
|
|
Status = g_Target->ReadIo(Isa, 0, 1, IoAddress, &InputValue, InputSize,
|
|
NULL);
|
|
|
|
dprintf("%s: ", FormatAddr64(IoAddress));
|
|
|
|
if (Status == S_OK)
|
|
{
|
|
Format[2] = (CHAR)('0' + (InputSize * 2));
|
|
dprintf(Format, InputValue);
|
|
}
|
|
else
|
|
{
|
|
while (InputSize--)
|
|
{
|
|
dprintf("??");
|
|
}
|
|
}
|
|
|
|
dprintf("\n");
|
|
}
|
|
|
|
/*** fnOutputIo - output io
|
|
*
|
|
* Purpose:
|
|
* Function of "ob, ow, od <address>" command.
|
|
*
|
|
* Write a value to the specified io address.
|
|
*
|
|
* Input:
|
|
* IoAddress - Address to read.
|
|
* OutputValue - Value to be written
|
|
* OutputType - The output size type 'b', 'w', or 'd'
|
|
*
|
|
* Output:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* No errors are returned.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void
|
|
fnOutputIo (
|
|
ULONG64 IoAddress,
|
|
ULONG OutputValue,
|
|
UCHAR OutputType
|
|
)
|
|
{
|
|
ULONG OutputSize = 1;
|
|
|
|
if (OutputType == 'w')
|
|
{
|
|
OutputSize = 2;
|
|
}
|
|
else if (OutputType == 'd')
|
|
{
|
|
OutputSize = 4;
|
|
}
|
|
|
|
g_Target->WriteIo(Isa, 0, 1, IoAddress, &OutputValue, OutputSize, NULL);
|
|
}
|