You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
609 lines
13 KiB
609 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1992-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
physical.cpp
|
|
|
|
Abstract:
|
|
Extensions to read/display physocal memory
|
|
|
|
Environment:
|
|
|
|
User Mode.
|
|
|
|
Revision History:
|
|
|
|
Kshitiz K. Sharma (kksharma) 5/9/2001
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define PHYS_READ_MATCH_DUMPSIZE 0x100
|
|
|
|
#define PHYS_FLAG_MESSAGE \
|
|
"If you know the caching attributes used for the memory,\n" \
|
|
"try specifying [c], [uc] or [wc], as in !dd [c] <params>.\n" \
|
|
"WARNING: Incorrect use of these flags will cause unpredictable\n" \
|
|
"processor corruption. This may immediately (or at any time in\n" \
|
|
"the future until reboot) result in a system hang, incorrect data\n" \
|
|
"being displayed or other strange crashes and corruption.\n"
|
|
|
|
ULONG64 g_LastAddress = 0;
|
|
|
|
VOID
|
|
ReadPhysicalInChunks(
|
|
ULONG64 Address,
|
|
PUCHAR Buffer,
|
|
ULONG BufferSize,
|
|
ULONG Flags,
|
|
ULONG ChunkSize,
|
|
PULONG ActualRead
|
|
)
|
|
{
|
|
if ((Flags & PHYS_READ_MATCH_DUMPSIZE) &&
|
|
(ChunkSize != 0)) {
|
|
DWORD i, ret;
|
|
PUCHAR pReadBuff;
|
|
|
|
Flags &= 0xf;
|
|
|
|
for (i=0, pReadBuff = Buffer; i<BufferSize;
|
|
i+=ChunkSize, pReadBuff+=ChunkSize) {
|
|
ReadPhysicalWithFlags(Address + i,
|
|
pReadBuff,ChunkSize,Flags,&ret);
|
|
if (ret != ChunkSize) {
|
|
break;
|
|
}
|
|
*ActualRead += ret;
|
|
}
|
|
} else {
|
|
Flags &= 0xf;
|
|
ReadPhysicalWithFlags(Address,Buffer,BufferSize,Flags,ActualRead);
|
|
}
|
|
return;
|
|
}
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps specified range of physical memory in given format
|
|
|
|
Arguments:
|
|
|
|
Address - Address to start
|
|
|
|
NumEntries - Number of entries to dump
|
|
|
|
EntrySize - Size of each entry
|
|
|
|
ShowAsAscii - print corresponding ascii chars
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
BOOL
|
|
DumpPhysicalMemory(
|
|
ULONG64 Address,
|
|
ULONG NumEntries,
|
|
ULONG EntrySize,
|
|
BOOL ShowAsAscii,
|
|
ULONG Flags
|
|
)
|
|
{
|
|
#define NumberBytesToRead 32*4
|
|
|
|
UCHAR Buffer[NumberBytesToRead];
|
|
ULONG ActualRead=0;
|
|
|
|
if ((EntrySize != 1) && (EntrySize != 2) && (EntrySize != 4) && (EntrySize != 8)) {
|
|
EntrySize=4;
|
|
}
|
|
while (1) {
|
|
if (CheckControlC()) {
|
|
break;
|
|
}
|
|
ReadPhysicalInChunks(Address,Buffer,sizeof(Buffer),Flags, EntrySize,&ActualRead);
|
|
if (ActualRead != sizeof(Buffer) &&
|
|
ActualRead < NumEntries*EntrySize) {
|
|
dprintf("Physical memory read at %I64lx failed\n", Address);
|
|
if (Flags == PHYS_FLAG_DEFAULT && ActualRead == 0) {
|
|
dprintf(PHYS_FLAG_MESSAGE);
|
|
}
|
|
return FALSE;
|
|
} else {
|
|
PCHAR DumpByte = (PCHAR)&Buffer[0], pRow;
|
|
ULONG cnt;
|
|
for(cnt=0;cnt<NumberBytesToRead;DumpByte+=EntrySize) {
|
|
if (!(cnt & 0xf)) {
|
|
dprintf("#%8I64lx", Address+cnt);
|
|
pRow = DumpByte;
|
|
}
|
|
switch (EntrySize) {
|
|
case 1:
|
|
dprintf("%c%02lx", ((cnt&0xf) == 8 ? '-' : ' '),*((PUCHAR)DumpByte));
|
|
break;
|
|
case 2:
|
|
dprintf(" %04lx", *((PUSHORT) DumpByte));
|
|
break;
|
|
case 4:
|
|
dprintf(" %08lx", *((PULONG) DumpByte));
|
|
break;
|
|
case 8:
|
|
dprintf(" %08lx'%08lx", *((PULONG) DumpByte), *((PULONG) (DumpByte+4)));
|
|
break;
|
|
}
|
|
|
|
cnt+=EntrySize, NumEntries--;
|
|
if ((cnt && !(cnt & 0xf)) || !NumEntries) {
|
|
if (ShowAsAscii) {
|
|
unsigned char ch;
|
|
dprintf(" ");
|
|
for (ULONG d=0; d < 16; d++) {
|
|
ch = (UCHAR) pRow[d];
|
|
if (ch < 0x20 || ch > 0x7e) {
|
|
ch = '.';
|
|
}
|
|
dprintf("%c", ch);
|
|
}
|
|
}
|
|
dprintf("\n");
|
|
|
|
}
|
|
if (!NumEntries) {
|
|
break;
|
|
}
|
|
}
|
|
Address += cnt;
|
|
if (!NumEntries) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
g_LastAddress = Address;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reverse sign extension of the value returned by GetExpression()
|
|
based on the assumption that no physical address may be bigger
|
|
than 0xfffffff00000000.
|
|
|
|
Arguments:
|
|
|
|
Val - points to the value to reverse sign extension
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
void
|
|
ReverseSignExtension(ULONG64* Val)
|
|
{
|
|
if ((*Val & 0xffffffff00000000) == 0xffffffff00000000)
|
|
{
|
|
*Val &= 0x00000000ffffffff;
|
|
}
|
|
}
|
|
|
|
PCSTR
|
|
GetPhyFlags(PCSTR Args, PULONG Flags)
|
|
{
|
|
*Flags = PHYS_FLAG_DEFAULT;
|
|
|
|
while (*Args && (*Args == ' ' || *Args == '\t')) {
|
|
++Args;
|
|
}
|
|
|
|
if (*Args == '[') {
|
|
Args++;
|
|
if (*Args == 'c') {
|
|
*Flags = PHYS_FLAG_CACHED;
|
|
Args++;
|
|
} else if (*Args == 'u' && *(Args + 1) == 'c') {
|
|
*Flags = PHYS_FLAG_UNCACHED;
|
|
Args += 2;
|
|
} else if (*Args == 'w' && *(Args + 1) == 'c') {
|
|
*Flags = PHYS_FLAG_WRITE_COMBINED;
|
|
Args += 2;
|
|
}
|
|
if (*Args != ']') {
|
|
*Flags = PHYS_FLAG_DEFAULT;
|
|
dprintf("Unknown physical memory caching attribute\n");
|
|
} else {
|
|
Args++;
|
|
}
|
|
}
|
|
if (*Args == '-' || *Args == '\\') {
|
|
++Args;
|
|
if (tolower(*Args) == 'm') {
|
|
*Flags |= PHYS_READ_MATCH_DUMPSIZE;
|
|
} else {
|
|
dprintf("Bad argument -%s\n", Args);
|
|
}
|
|
++Args;
|
|
}
|
|
return Args;
|
|
}
|
|
|
|
void
|
|
GetPhyDumpArgs(
|
|
PCSTR Args,
|
|
PULONG64 Address,
|
|
PULONG Range,
|
|
PULONG Flags
|
|
)
|
|
{
|
|
CHAR Buffer[100]={0};
|
|
|
|
*Flags = PHYS_FLAG_DEFAULT;
|
|
|
|
if(*Args == '\0') {
|
|
*Address=g_LastAddress;
|
|
} else {
|
|
Args = GetPhyFlags(Args, Flags);
|
|
while (*Args && (*Args == ' ' || *Args == '\t')) {
|
|
++Args;
|
|
}
|
|
if(*Args == '\0') {
|
|
*Address=g_LastAddress;
|
|
} else {
|
|
GetExpressionEx(Args, Address, &Args);
|
|
ReverseSignExtension(Address);
|
|
*Address &= (~0x3); // Truncate to dword boundary
|
|
g_LastAddress=*Address;
|
|
while (*Args && (*Args == ' ' || *Args == '\t')) {
|
|
++Args;
|
|
}
|
|
if (*Args == 'l' || *Args == 'L') {
|
|
++Args;
|
|
*Range = (ULONG) GetExpression(Args);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
DECLARE_API( db )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does a read of 16 ULONGS from the physical memory of the target machine
|
|
|
|
Arguments:
|
|
|
|
args - Supplies physical address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG64 Address = 0;
|
|
ULONG Range = 0;
|
|
ULONG Flags;
|
|
|
|
GetPhyDumpArgs(args, &Address, &Range, &Flags);
|
|
if (!Range) {
|
|
Range = 128;
|
|
}
|
|
DumpPhysicalMemory(Address, Range, 1, TRUE, Flags);
|
|
return S_OK;
|
|
}
|
|
|
|
DECLARE_API( dd )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does a read of 16 ULONGS from the physical memory of the target machine
|
|
|
|
Arguments:
|
|
|
|
args - Supplies physical address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG64 Address = 0;
|
|
ULONG Range = 0;
|
|
ULONG Flags;
|
|
|
|
GetPhyDumpArgs(args, &Address, &Range, &Flags);
|
|
if (!Range) {
|
|
Range = 32;
|
|
}
|
|
DumpPhysicalMemory(Address, Range, 4, FALSE, Flags);
|
|
return S_OK;
|
|
}
|
|
|
|
DECLARE_API( dw )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does a read of 16 ULONGS from the physical memory of the target machine
|
|
|
|
Arguments:
|
|
|
|
args - Supplies physical address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG64 Address = 0;
|
|
ULONG Range = 0;
|
|
ULONG Flags;
|
|
|
|
GetPhyDumpArgs(args, &Address, &Range, &Flags);
|
|
if (!Range) {
|
|
Range = 64;
|
|
}
|
|
DumpPhysicalMemory(Address, Range, 2, FALSE, Flags);
|
|
return S_OK;
|
|
}
|
|
|
|
DECLARE_API( dp )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does a read of 16 ULONGS from the physical memory of the target machine
|
|
|
|
Arguments:
|
|
|
|
args - Supplies physical address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG64 Address = 0;
|
|
ULONG Range = 0;
|
|
ULONG Flags;
|
|
|
|
GetPhyDumpArgs(args, &Address, &Range, &Flags);
|
|
if (!Range) {
|
|
Range = IsPtr64() ? 16 : 32;
|
|
}
|
|
DumpPhysicalMemory(Address, Range, IsPtr64() ? 8 : 4, FALSE, Flags);
|
|
return S_OK;
|
|
}
|
|
DECLARE_API( dc )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does a read of N ULONGS from the physical memory of the target machine,
|
|
dumping both hex and ASCII.
|
|
|
|
Arguments:
|
|
|
|
args - Supplies physical address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG64 Address = 0;
|
|
ULONG Range = 0;
|
|
ULONG Flags;
|
|
|
|
GetPhyDumpArgs(args, &Address, &Range, &Flags);
|
|
if (!Range) {
|
|
Range = 32;
|
|
}
|
|
DumpPhysicalMemory(Address, Range, 4, TRUE, Flags);
|
|
return S_OK;
|
|
}
|
|
|
|
DECLARE_API( du )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does a read of 16 ULONGS from the physical memory of the target machine
|
|
|
|
Arguments:
|
|
|
|
args - Supplies physical address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG64 Address = 0;
|
|
ULONG Range = 0, ActualRead;
|
|
WCHAR Buffer[MAX_PATH]={0};
|
|
ULONG Flags;
|
|
|
|
GetPhyDumpArgs(args, &Address, &Range, &Flags);
|
|
if (Range>MAX_PATH) {
|
|
Range = MAX_PATH;
|
|
}
|
|
if (!Range) {
|
|
Range = 16;
|
|
}
|
|
ReadPhysicalWithFlags(Address,Buffer,Range * sizeof(WCHAR),Flags,&ActualRead);
|
|
if (ActualRead != Range*sizeof(WCHAR)) {
|
|
dprintf("Physical memory read at %I64lx failed\n", Address);
|
|
if (Flags == PHYS_FLAG_DEFAULT && ActualRead == 0) {
|
|
dprintf(PHYS_FLAG_MESSAGE);
|
|
}
|
|
return FALSE;
|
|
} else {
|
|
ULONG cnt;
|
|
|
|
dprintf("#%8I64lx \"", Address);
|
|
for (ULONG d=0; d < Range; d++) {
|
|
WCHAR ch = Buffer[d];
|
|
if (ch == 0) {
|
|
break;
|
|
}
|
|
if (ch < 0x20 || ch > 0x7e) {
|
|
ch = '.';
|
|
}
|
|
dprintf("%wc", ch);
|
|
}
|
|
dprintf("\"\n");
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
DECLARE_API( ed )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes a sequence of ULONGs into a given physical address on the
|
|
target machine.
|
|
|
|
Arguments:
|
|
|
|
arg - Supplies both the target address and the data in the form of
|
|
"PHYSICAL_ADDRESS ULONG [ULONG, ULONG,...]"
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 Address = 0;
|
|
ULONG Buffer;
|
|
ULONG ActualWritten=0;
|
|
PCHAR NextToken;
|
|
ULONG Flags;
|
|
|
|
args = GetPhyFlags(args, &Flags);
|
|
|
|
Address = GetExpression(args);
|
|
|
|
strtok((PSTR)args," \t,"); // The first token is the address
|
|
|
|
// Since we're picking off one ULONG at a time, we'll make
|
|
// one DbgKdWritePhysicalMemoryAddress call per ULONG. This
|
|
// is slow, but easy to code.
|
|
while((NextToken=strtok(NULL," \t,")) != NULL) {
|
|
if (!sscanf(NextToken,"%lx",&Buffer)) {
|
|
break;
|
|
}
|
|
WritePhysicalWithFlags(Address,&Buffer,sizeof(Buffer),Flags,
|
|
&ActualWritten);
|
|
if (ActualWritten != sizeof(Buffer)) {
|
|
dprintf("Physical memory write at %I64lx failed\n", Address);
|
|
if (Flags == PHYS_FLAG_DEFAULT && ActualWritten == 0) {
|
|
dprintf(PHYS_FLAG_MESSAGE);
|
|
}
|
|
}
|
|
Address+=sizeof(Buffer);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
DECLARE_API( eb )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes a sequence of BYTEs into a given physical address on the
|
|
target machine.
|
|
|
|
Arguments:
|
|
|
|
arg - Supplies both the target address and the data in the form of
|
|
"PHYSICAL_ADDRESS ULONG [ULONG, ULONG,...]"
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 Address = 0;
|
|
ULONG Buffer;
|
|
UCHAR c;
|
|
ULONG ActualWritten;
|
|
PCHAR NextToken;
|
|
ULONG Flags;
|
|
|
|
UNREFERENCED_PARAMETER (Client);
|
|
|
|
args = GetPhyFlags(args, &Flags);
|
|
|
|
Address = GetExpression(args);
|
|
|
|
strtok((PSTR)args," \t,"); // The first token is the address
|
|
|
|
// Since we're picking off one BYTE at a time, we'll make
|
|
// one DbgKdWritePhysicalMemoryAddress call per BYTE. This
|
|
// is slow, but easy to code.
|
|
while((NextToken=strtok(NULL," \t,")) != NULL) {
|
|
if (!sscanf(NextToken,"%lx",&Buffer)) {
|
|
break;
|
|
}
|
|
c = (UCHAR)Buffer;
|
|
WritePhysicalWithFlags(Address,&c,sizeof(UCHAR),Flags,&ActualWritten);
|
|
if (ActualWritten != sizeof(UCHAR)) {
|
|
dprintf("Physical memory write at %I64lx failed\n", Address);
|
|
if (Flags == PHYS_FLAG_DEFAULT && ActualWritten == 0) {
|
|
dprintf(PHYS_FLAG_MESSAGE);
|
|
}
|
|
}
|
|
Address+=sizeof(UCHAR);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|