|
|
//----------------------------------------------------------------------------
//
// Functions dealing with memory access, such as reading, writing,
// dumping and entering.
//
// Copyright (C) Microsoft Corporation, 1997-2002.
//
//----------------------------------------------------------------------------
#include "ntsdp.hpp"
TypedData g_LastDump;
ADDR g_DumpDefault; // default dump address
#define MAX_VFN_TABLE_OFFSETS 16
ULONG g_ObjVfnTableOffset[MAX_VFN_TABLE_OFFSETS]; ULONG64 g_ObjVfnTableAddr[MAX_VFN_TABLE_OFFSETS]; ULONG g_NumObjVfnTableOffsets;
BOOL CALLBACK LocalSymbolEnumerator(PSYMBOL_INFO SymInfo, ULONG Size, PVOID Context) { ULONG64 Value = g_Machine->CvRegToMachine((CV_HREG_e)SymInfo->Register); ULONG64 Address = SymInfo->Address;
TranslateAddress(SymInfo->ModBase, SymInfo->Flags, (ULONG)Value, &Address, &Value); VerbOut("%s ", FormatAddr64(Address)); dprintf("%15s = ", SymInfo->Name); if (SymInfo->Flags & SYMFLAG_REGISTER) { dprintf("%I64x\n", Value); } else { if (!DumpSingleValue(SymInfo)) { dprintf("??"); } dprintf("\n"); }
if (CheckUserInterrupt()) { return FALSE; }
return TRUE; }
void ParseDumpCommand(void) { CHAR Ch; ULONG64 Count; ULONG Size; ULONG Offset; BOOL DumpSymbols;
static CHAR s_DumpPrimary = 'b'; static CHAR s_DumpSecondary = ' ';
if (!IS_CUR_MACHINE_ACCESSIBLE()) { error(BADTHREAD); } 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, DEFAULT_RANGE_LIMIT); DumpAsciiMemory(&g_DumpDefault, (ULONG)Count); break;
case 'b': Count = 128; GetRange(&g_DumpDefault, &Count, 1, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpByteMemory(&g_DumpDefault, (ULONG)Count); break;
case 'c': Count = 32; GetRange(&g_DumpDefault, &Count, 4, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpDwordAndCharMemory(&g_DumpDefault, (ULONG)Count); break;
case 'd': Count = 32; DumpSymbols = s_DumpSecondary == 's'; GetRange(&g_DumpDefault, &Count, 4, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpDwordMemory(&g_DumpDefault, (ULONG)Count, DumpSymbols); break;
case 'D': Count = 15; GetRange(&g_DumpDefault, &Count, 8, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpDoubleMemory(&g_DumpDefault, (ULONG)Count); break;
case 'f': Count = 16; GetRange(&g_DumpDefault, &Count, 4, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpFloatMemory(&g_DumpDefault, (ULONG)Count); break;
case 'g': Offset = (ULONG)GetExpression(); Count = 8; if (*g_CurCmd && *g_CurCmd != ';') { Count = (ULONG)GetExpression() - Offset; // It's unlikely that people want to dump hundreds
// of selectors. People often mistake the second
// number for a count and if it's less than the
// first they'll end up with a negative count.
if (Count > 0x800) { error(BADRANGE); } } DumpSelector(Offset, (ULONG)Count); 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(); } } } DumpListMemory(&g_DumpDefault, (ULONG)Count, Size, followBlink); break;
case 'q': Count = 16; DumpSymbols = s_DumpSecondary == 's'; GetRange(&g_DumpDefault, &Count, 8, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpQuadMemory(&g_DumpDefault, (ULONG)Count, DumpSymbols); break;
case 's': case 'S': UNICODE_STRING64 UnicodeString; ADDR BufferAddr;
Count = 1; GetRange(&g_DumpDefault, &Count, 2, SEGREG_DATA, DEFAULT_RANGE_LIMIT); while (Count--) { if (g_Target->ReadUnicodeString(g_Process, g_Machine, Flat(g_DumpDefault), &UnicodeString) == S_OK) { ADDRFLAT(&BufferAddr, UnicodeString.Buffer); if (s_DumpPrimary == 'S') { DumpUnicodeMemory( &BufferAddr, UnicodeString.Length / sizeof(WCHAR)); } else { DumpAsciiMemory( &BufferAddr, UnicodeString.Length ); } } } break;
case 't': case 'T': SymbolTypeDumpEx(g_Process->m_SymHandle, g_Process->m_ImageHead, g_CurCmd); break;
case 'u': Count = 384; GetRange(&g_DumpDefault, &Count, 2, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpUnicodeMemory(&g_DumpDefault, (ULONG)Count); break;
case 'v': RequireCurrentScope(); EnumerateLocals(LocalSymbolEnumerator, NULL); break;
case 'w': Count = 64; GetRange(&g_DumpDefault, &Count, 2, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpWordMemory(&g_DumpDefault, (ULONG)Count); break;
case 'y': switch(s_DumpSecondary) { case 'b': Count = 32; GetRange(&g_DumpDefault, &Count, 1, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpByteBinaryMemory(&g_DumpDefault, (ULONG)Count); break;
case 'd': Count = 8; GetRange(&g_DumpDefault, &Count, 4, SEGREG_DATA, DEFAULT_RANGE_LIMIT); DumpDwordBinaryMemory(&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 void GetValue(TypedData* Val) = 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);
if (fnotFlat(*Start) || g_Target->ReadVirtual(g_Process, Flat(*Start), ReadBuffer, Block * m_Size, &Read) != S_OK) { Read = 0; } Read /= 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; GetValue(&g_LastDump); g_LastDump.SetDataSource(TDATA_MEMORY, Flat(*Start), 0); }
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.
}
/*** DumpAsciiMemory - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); virtual void EndRow(void);
UCHAR m_Buf[33]; };
void DumpAscii::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_CHAR); Val->m_S8 = *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 DumpAsciiMemory(PADDR Start, ULONG Count) { DumpAscii Dumper;
return Count - Dumper.Dump(Start, Count); }
/*** DumpUnicodeMemory - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); virtual void EndRow(void);
WCHAR m_Buf[33]; };
void DumpUnicode::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_WCHAR_T); Val->m_U16 = *(WCHAR *)m_Value; }
BOOL DumpUnicode::PrintValue(void) { WCHAR ch;
ch = *(WCHAR *)m_Value; if (ch == UNICODE_NULL) { return FALSE; }
if (!iswprint(ch)) { 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 DumpUnicodeMemory(PADDR Start, ULONG Count) { DumpUnicode Dumper;
return Count - Dumper.Dump(Start, Count); }
/*** DumpByteMemory - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); virtual void EndRow(void);
UCHAR m_Buf[17]; };
void DumpByte::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_UINT8); Val->m_U8 = *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 DumpByteMemory(PADDR Start, ULONG Count) { DumpByte Dumper;
Dumper.Dump(Start, Count); }
/*** DumpWordMemory - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); };
void DumpWord::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_UINT16); Val->m_U16 = *(WORD *)m_Value; }
BOOL DumpWord::PrintValue(void) { dprintf(" %04x", *(WORD *)m_Value); return TRUE; }
void DumpWord::PrintUnknown(void) { dprintf(" ????"); }
void DumpWordMemory(PADDR Start, ULONG Count) { DumpWord Dumper; Dumper.Dump(Start, Count); }
/*** DumpDwordMemory - 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 * ShowSymbols - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void);
BOOL m_DumpSymbols; };
void DumpDword::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_UINT32); Val->m_U32 = *(DWORD *)m_Value; }
BOOL DumpDword::PrintValue(void) { CHAR SymBuf[MAX_SYMBOL_LEN]; ULONG64 Displacement;
dprintf(" %08lx", *(DWORD *)m_Value);
if (m_DumpSymbols) { GetSymbol(EXTEND64(*(LONG *)m_Value), SymBuf, sizeof(SymBuf), &Displacement); 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 DumpDwordMemory(PADDR Start, ULONG Count, BOOL ShowSymbols) { DumpDword Dumper(ShowSymbols);
Dumper.Dump(Start, Count); }
/*** DumpDwordAndCharMemory - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); virtual void EndRow(void);
UCHAR m_Buf[17]; };
void DumpDwordAndChar::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_UINT32); Val->m_U32 = *(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 DumpDwordAndCharMemory(PADDR Start, ULONG Count) { DumpDwordAndChar Dumper;
Dumper.Dump(Start, Count); }
/*** DumpListMemory - 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 DumpListMemory(PADDR Start, ULONG ElemCount, ULONG Size, BOOL FollowBlink) { ULONG64 FirstAddr; ULONG64 Link; LIST_ENTRY64 List; ADDR CurAddr;
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_Process, g_Machine, Flat(*Start), &List) != S_OK) { break; } Link = List.Blink; } else { if (g_Target->ReadPointer(g_Process, g_Machine, Flat(*Start), &Link) != S_OK) { break; } }
CurAddr = *Start; if (g_Machine->m_Ptr64) { DumpQuadMemory(&CurAddr, Size, FALSE); } else { DumpDwordMemory(&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; } } }
//----------------------------------------------------------------------------
//
// DumpFloatMemory
//
// Dumps float values.
//
//----------------------------------------------------------------------------
class DumpFloat : public DumpValues { public: DumpFloat(void) : DumpValues(sizeof(float), 4) {}
protected: // Worker methods that derived classes must define.
virtual void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); };
void DumpFloat::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_FLOAT32); Val->m_F32 = *(float *)m_Value; }
BOOL DumpFloat::PrintValue(void) { dprintf(" %16.8g", *(float *)m_Value); return TRUE; }
void DumpFloat::PrintUnknown(void) { dprintf(" ????????????????"); }
void DumpFloatMemory(PADDR Start, ULONG Count) { DumpFloat Dumper; Dumper.Dump(Start, Count); }
//----------------------------------------------------------------------------
//
// DumpDoubleMemory
//
// Dumps double values.
//
//----------------------------------------------------------------------------
class DumpDouble : public DumpValues { public: DumpDouble(void) : DumpValues(sizeof(double), 3) {}
protected: // Worker methods that derived classes must define.
virtual void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); };
void DumpDouble::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_FLOAT64); Val->m_F64 = *(double *)m_Value; }
BOOL DumpDouble::PrintValue(void) { dprintf(" %22.12lg", *(double *)m_Value); return TRUE; }
void DumpDouble::PrintUnknown(void) { dprintf(" ????????????????????????"); }
void DumpDoubleMemory(PADDR Start, ULONG Count) { DumpDouble Dumper; Dumper.Dump(Start, Count); }
/*** DumpQuadMemory - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void);
BOOL m_DumpSymbols; };
void DumpQuad::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_UINT64); Val->m_U64 = *(ULONG64 *)m_Value; }
BOOL DumpQuad::PrintValue(void) { CHAR SymBuf[MAX_SYMBOL_LEN]; ULONG64 Displacement;
ULONG64 Val = *(ULONG64*)m_Value; dprintf(" %08lx`%08lx", (ULONG)(Val >> 32), (ULONG)Val);
if (m_DumpSymbols) { GetSymbol(Val, SymBuf, sizeof(SymBuf), &Displacement); 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 DumpQuadMemory(PADDR Start, ULONG Count, BOOL ShowSymbols) { DumpQuad Dumper(ShowSymbols);
Dumper.Dump(Start, Count); }
/*** DumpByteBinaryMemory - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); virtual void EndRow(void);
UCHAR m_HexValue[13]; };
void DumpByteBinary::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_UINT8); Val->m_U8 = *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 DumpByteBinaryMemory(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); }
/*** DumpDwordBinaryMemory - 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 void GetValue(TypedData* Val); virtual BOOL PrintValue(void); virtual void PrintUnknown(void); virtual void EndRow(void);
UCHAR m_HexValue[9]; };
void DumpDwordBinary::GetValue(TypedData* Val) { Val->SetToNativeType(DNTYPE_UINT32); Val->m_U32 = *(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 DumpDwordBinaryMemory(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); }
//----------------------------------------------------------------------------
//
// DumpSelector
//
// Dumps x86 selectors.
//
//----------------------------------------------------------------------------
void DumpSelector(ULONG Selector, ULONG Count) { DESCRIPTOR64 Desc; ULONG Type; LPSTR TypeName, TypeProtect, TypeAccess; PSTR PreFill, PostFill, Dash;
if (g_Machine->m_Ptr64) { PreFill = " "; PostFill = " "; Dash = "---------"; } else { PreFill = ""; PostFill = ""; Dash = ""; } dprintf("Selector %sBase%s %sLimit%s " "Type DPL Size Gran Pres\n", PreFill, PostFill, PreFill, PostFill); dprintf("-------- --------%s --------%s " "---------- --- ------- ---- ----\n", Dash, Dash); while (Count >= 8) { if (CheckUserInterrupt()) { WarnOut("-- User interrupt\n"); break; } dprintf(" %04X ", Selector); if (g_Target->GetSelDescriptor(g_Thread, g_Machine, Selector, &Desc) != S_OK) { ErrOut("Unable to get descriptor\n"); Count -= 8; Selector += 8; continue; }
Type = X86_DESC_TYPE(Desc.Flags); if (Type & 0x10) { if (Type & 0x8) { // Code Descriptor
TypeName = "Code "; TypeProtect = (Type & 2) ? "RE" : "EO"; } else { // Data Descriptor
TypeName = "Data "; TypeProtect = (Type & 2) ? "RW" : "RO"; }
TypeAccess = (Type & 1) ? " Ac" : " "; } else { TypeProtect = ""; TypeAccess = ""; switch(Type) { case 2: TypeName = "LDT "; break; case 1: case 3: case 9: case 0xB: TypeName = (Type & 0x8) ? "TSS32" : "TSS16"; TypeAccess = (Type & 0x2) ? " Busy" : " Avl "; break; case 4: TypeName = "C-GATE16 "; break; case 5: TypeName = "TSK-GATE "; break; case 6: TypeName = "I-GATE16 "; break; case 7: TypeName = "TRP-GATE16"; break; case 0xC: TypeName = "C-GATE32 "; break; case 0xF: TypeName = "T-GATE32 "; break; default: TypeName = "<Reserved>"; break; } }
dprintf("%s %s %s%s%s %d %s %s %s\n", FormatAddr64(Desc.Base), FormatAddr64(Desc.Limit), TypeName, TypeProtect, TypeAccess, X86_DESC_PRIVILEGE(Desc.Flags), (Desc.Flags & X86_DESC_DEFAULT_BIG) ? " Big " : "Not Big", (Desc.Flags & X86_DESC_GRANULARITY) ? "Page" : "Byte", (Desc.Flags & X86_DESC_PRESENT) ? " P " : " NP ");
Count -= 8; Selector += 8; } }
void ParseEnterCommand(void) { CHAR Ch; ADDR Addr1; UCHAR ListBuffer[STRLISTSIZE * 2]; ULONG Count; ULONG Size;
static CHAR s_EnterType = 'b';
if (!IS_CUR_MACHINE_ACCESSIBLE()) { error(BADTHREAD); } Ch = (CHAR)tolower(*g_CurCmd); if (Ch == 'a' || Ch == 'b' || Ch == 'w' || Ch == 'd' || Ch == 'q' || Ch == 'u' || Ch == 'p' || Ch == 'f') { if (*g_CurCmd == 'D') { s_EnterType = *g_CurCmd; } else { s_EnterType = Ch; } g_CurCmd++; } GetAddrExpression(SEGREG_DATA, &Addr1); if (s_EnterType == 'a' || s_EnterType == 'u') { AsciiList((PSTR)ListBuffer, sizeof(ListBuffer), &Count); if (Count == 0) { error(UNIMPLEMENT); //TEMP
}
if (s_EnterType == 'u') { ULONG Ansi; // Expand ANSI to Unicode.
Ansi = Count; Count *= 2; while (Ansi-- > 0) { ListBuffer[Ansi * 2] = ListBuffer[Ansi]; ListBuffer[Ansi * 2 + 1] = 0; } Size = 2; } else { Size = 1; } } else { Size = 1; if (s_EnterType == 'w') { Size = 2; } else if (s_EnterType == 'd' || s_EnterType == 'f' || (s_EnterType == 'p' && !g_Machine->m_Ptr64)) { Size = 4; } else if (s_EnterType == 'q' || s_EnterType == 'D' || (s_EnterType == 'p' && g_Machine->m_Ptr64)) { Size = 8; }
if (s_EnterType == 'f' || s_EnterType == 'D') { FloatList(ListBuffer, sizeof(ListBuffer), Size, &Count); } else { HexList(ListBuffer, sizeof(ListBuffer), Size, &Count); } if (Count == 0) { InteractiveEnterMemory(s_EnterType, &Addr1, Size); return; } }
//
// Memory was entered at the command line.
// Write it out in the same chunks as it was entered.
//
PUCHAR List = &ListBuffer[0];
while (Count) { if (fnotFlat(Addr1) || g_Target->WriteAllVirtual(g_Process, Flat(Addr1), List, Size) != S_OK) { error(MEMORY); } AddrAdd(&Addr1, Size); if (CheckUserInterrupt()) { WarnOut("-- User interrupt\n"); return; }
List += Size; Count -= Size; } }
//----------------------------------------------------------------------------
//
// InteractiveEnterMemory
//
// Interactively walks through memory, displaying current contents
// and prompting for new contents.
//
//----------------------------------------------------------------------------
void InteractiveEnterMemory(CHAR Type, 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 (fnotFlat(*Address) || g_Target->ReadAllVirtual(g_Process, Flat(*Address), &Content, Size) != S_OK) { error(MEMORY); } dprintAddr(Address);
switch(Type) { case 'f': dprintf("%12.6g", *(float*)&Content); break; case 'D': dprintf("%22.12g", *(double*)&Content); break; default: 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; } break; }
GetInput(" ", EnterBuf, 1024, GETIN_LOG_INPUT_LINE); 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; if (Type == 'f' || Type == 'D') { EnteredValue = FloatValue(Size); } else { EnteredValue = HexValue(Size); }
if (fnotFlat(*Address) || g_Target->WriteAllVirtual(g_Process, Flat(*Address), &EnteredValue, Size) != S_OK) { error(MEMORY); } AddrAdd(Address, Size); } }
/*** CompareTargetMemory - 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 CompareTargetMemory(PADDR Src1Addr, ULONG Length, PADDR Src2Addr) { ULONG CompIndex; UCHAR Src1Ch; UCHAR Src2Ch;
for (CompIndex = 0; CompIndex < Length; CompIndex++) { if (fnotFlat(*Src1Addr) || fnotFlat(*Src2Addr) || g_Target->ReadAllVirtual(g_Process, Flat(*Src1Addr), &Src1Ch, sizeof(Src1Ch)) != S_OK || g_Target->ReadAllVirtual(g_Process, Flat(*Src2Addr), &Src2Ch, sizeof(Src2Ch)) != S_OK) { 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; } } }
/*** MoveTargetMemory - 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 MoveTargetMemory(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 (fnotFlat(*SrcAddr) || fnotFlat(*DestAddr) || g_Target->ReadAllVirtual(g_Process, Flat(*SrcAddr), &Ch, sizeof(Ch)) || g_Target->WriteAllVirtual(g_Process, Flat(*DestAddr), &Ch, sizeof(Ch)) != S_OK) { error(MEMORY); } AddrAdd(SrcAddr, Incr); AddrAdd(DestAddr, Incr); if (CheckUserInterrupt()) { WarnOut("-- User interrupt\n"); return; } } }
/*** ParseFillMemory - 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, DEFAULT_RANGE_LIMIT); HexList(Pattern, sizeof(Pattern), 1, &PatternSize); if (PatternSize == 0) { error(SYNTAX); }
if (Virtual) { Status = g_Target->FillVirtual(g_Process, 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); } }
/*** SearchTargetMemory - search memory for a set of bytes
* * 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 SearchTargetMemory(PADDR Start, ULONG64 Length, PUCHAR List, ULONG Count, ULONG Granularity) { ADDR TmpAddr = *Start; ULONG64 Found; LONG64 SearchLength = Length; HRESULT Status;
do { Status = g_Target->SearchVirtual(g_Process, Flat(*Start), SearchLength, List, Count, Granularity, &Found); if (Status == S_OK) { ADDRFLAT(&TmpAddr, Found); switch(Granularity) { case 1: DumpByteMemory(&TmpAddr, 16); break; case 2: DumpWordMemory(&TmpAddr, 8); break; case 4: DumpDwordAndCharMemory(&TmpAddr, 4); break; case 8: DumpQuadMemory(&TmpAddr, 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("-- Memory search interrupted at %s\n", FormatAddr64(Flat(*Start))); return; } } } while (SearchLength > 0 && Status == S_OK); }
ULONG ObjVfnTableCallback(PFIELD_INFO FieldInfo, PVOID Context) { HRESULT Status; ULONG Index = g_NumObjVfnTableOffsets++; if (g_NumObjVfnTableOffsets > MAX_VFN_TABLE_OFFSETS) { return S_OK; } if ((Status = g_Target-> ReadPointer(g_Process, g_Machine, FieldInfo->address, &g_ObjVfnTableAddr[Index])) != S_OK) { ErrOut("Unable to read vtable pointer at %s\n", FormatAddr64(FieldInfo->address)); g_NumObjVfnTableOffsets--; return Status; }
g_ObjVfnTableOffset[Index] = FieldInfo->FieldOffset; return S_OK; }
void SearchForObjectByVfnTable(ULONG64 Start, ULONG64 Length, ULONG Granularity) { HRESULT Status; ULONG i; char Save; PSTR Str = StringValue(STRV_SPACE_IS_SEPARATOR || STRV_TRIM_TRAILING_SPACE || STRV_ESCAPED_CHARACTERS, &Save);
//
// Search all of the object's members for vtable references
// and collect them.
//
SYM_DUMP_PARAM Symbol; FIELD_INFO Fields[] = { {(PUCHAR)"__VFN_table", NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, (PVOID)&ObjVfnTableCallback}, }; ULONG Err;
ZeroMemory(&Symbol, sizeof(Symbol)); Symbol.sName = (PUCHAR)Str; Symbol.nFields = 1; Symbol.Context = (PVOID)Str; Symbol.Fields = Fields; Symbol.size = sizeof(Symbol); Symbol.Options = NO_PRINT;
g_NumObjVfnTableOffsets = 0; SymbolTypeDumpNew(&Symbol, &Err);
if (g_NumObjVfnTableOffsets == 0) { ErrOut("Object '%s' has no vtables\n", Str); *g_CurCmd = Save; return; }
TypedData SymbolType;
if ((Err = SymbolType. FindSymbol(g_Process, Str, TDACC_REQUIRE, g_Machine->m_Ptr64 ? 8 : 4)) || (SymbolType.IsPointer() && (Err = SymbolType.ConvertToDereference(TDACC_REQUIRE, g_Machine->m_Ptr64 ? 8 : 4)))) { error(Err); } if (!SymbolType.m_Image) { error(TYPEDATA); } if (g_NumObjVfnTableOffsets > MAX_VFN_TABLE_OFFSETS) { WarnOut("%s has %d vtables, limiting search to %d\n", Str, g_NumObjVfnTableOffsets, MAX_VFN_TABLE_OFFSETS); g_NumObjVfnTableOffsets = MAX_VFN_TABLE_OFFSETS; }
dprintf("%s size 0x%x, vtables: %d\n", Str, Symbol.TypeSize, g_NumObjVfnTableOffsets); for (i = 0; i < g_NumObjVfnTableOffsets; i++) { dprintf(" +%03x - %s ", g_ObjVfnTableOffset[i], FormatAddr64(g_ObjVfnTableAddr[i])); OutputSymAddr(g_ObjVfnTableAddr[i], 0, NULL); dprintf("\n"); } dprintf("Searching...\n");
*g_CurCmd = Save; //
// Scan memory for the first vtable pointer found. On
// a hit, check that all of the other vtable pointers
// match also.
//
do { ULONG64 Found; Status = g_Target->SearchVirtual(g_Process, Start, Length, &g_ObjVfnTableAddr[0], Granularity, Granularity, &Found); if (Status == S_OK) { // We found a hit on the first pointer. Check
// the others now.
Found -= g_ObjVfnTableOffset[0]; for (i = 1; i < g_NumObjVfnTableOffsets; i++) { ULONG64 Ptr;
if (g_Target->ReadPointer(g_Process, g_Machine, Found + g_ObjVfnTableOffset[i], &Ptr) != S_OK || Ptr != g_ObjVfnTableAddr[i]) { break; } }
if (i == g_NumObjVfnTableOffsets) { OutputTypeByIndex(g_Process->m_SymHandle, SymbolType.m_Image->m_BaseOfImage, SymbolType.m_BaseType, Found); } // Flush out the output immediately so that
// the user can see partial results during long searches.
FlushCallbacks();
Found += Symbol.TypeSize;
if (Found > Start) { Length -= Found - Start; } else { Length = 0; } Start = Found; if (CheckUserInterrupt()) { WarnOut("-- User interrupt\n"); return; } } } while (Length > 0 && Status == S_OK); }
void ParseSearchMemory(void) { ADDR Addr; ULONG64 Length; UCHAR Pat[STRLISTSIZE]; ULONG PatLen; ULONG Gran; char SearchType;
while (*g_CurCmd == ' ') { g_CurCmd++; }
Gran = 1; SearchType = 'b';
if (*g_CurCmd == '-') { g_CurCmd++; SearchType = *g_CurCmd; switch(SearchType) { case 'a': Gran = 1; break; case 'u': case 'w': Gran = 2; break; case 'd': Gran = 4; break; case 'q': Gran = 8; break; case 'v': // Special object vtable search. It's basically a multi-pointer
// search, so the granularity is pointer-size.
if (g_Machine->m_Ptr64) { Gran = 8; } else { Gran = 4; } break; default: error(SYNTAX); break; } g_CurCmd++; }
// Allow very large ranges for search as it is used
// to search large areas of memory.
ADDRFLAT(&Addr, 0); Length = 16; GetRange(&Addr, &Length, Gran, SEGREG_DATA, 0x10000000); if (!fFlat(Addr)) { error(BADRANGE); } if (SearchType == 'v') { SearchForObjectByVfnTable(Flat(Addr), Length * Gran, Gran); return; } else if (SearchType == 'a' || SearchType == 'u') { char Save; PSTR Str = StringValue(STRV_SPACE_IS_SEPARATOR || STRV_TRIM_TRAILING_SPACE || STRV_ESCAPED_CHARACTERS, &Save); PatLen = strlen(Str); if (PatLen * Gran > STRLISTSIZE) { error(LISTSIZE); } if (SearchType == 'u') { MultiByteToWideChar(CP_ACP, 0, Str, PatLen, (PWSTR)Pat, STRLISTSIZE / sizeof(WCHAR)); PatLen *= sizeof(WCHAR); } else { memcpy(Pat, Str, PatLen); } *g_CurCmd = Save; } else { HexList(Pat, sizeof(Pat), Gran, &PatLen); } if (PatLen == 0) { PCSTR Err = "Search pattern missing from"; ReportError(SYNTAX, &Err); } SearchTargetMemory(&Addr, Length * Gran, Pat, PatLen, Gran); }
/*** InputIo - 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 InputIo(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"); }
/*** OutputIo - 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 OutputIo(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); }
|