Leaked source code of windows server 2003
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.
 
 
 
 
 
 

601 lines
14 KiB

/*++
Copyright (c) 1999-2001 Microsoft Corporation
Module Name:
mmap.cpp
Abstract:
Implementation of memory map class.
Author:
Matthew D Hendel (math) 16-Sep-1999
Revision History:
--*/
#include "ntsdp.hpp"
MappedMemoryMap::MappedMemoryMap(void)
{
m_RegionCount = 0;
m_List = NULL;
}
MappedMemoryMap::~MappedMemoryMap(void)
{
PMEMORY_MAP_ENTRY Entry;
PMEMORY_MAP_ENTRY Next;
Entry = m_List;
while ( Entry != NULL )
{
Next = Entry->Next;
free ( Entry );
Entry = Next;
}
}
PMEMORY_MAP_ENTRY
MappedMemoryMap::AddMapEntry(ULONG64 BaseOfRegion, ULONG SizeOfRegion,
PVOID Buffer, PVOID UserData,
BOOL AllowOverlap)
{
PMEMORY_MAP_ENTRY PrevEntry;
PMEMORY_MAP_ENTRY MapEntry;
MapEntry = (MEMORY_MAP_ENTRY *)malloc ( sizeof ( MEMORY_MAP_ENTRY ) );
if (!MapEntry)
{
return NULL;
}
MapEntry->BaseOfRegion = BaseOfRegion;
MapEntry->SizeOfRegion = SizeOfRegion;
MapEntry->Region = Buffer;
MapEntry->UserData = UserData;
MapEntry->AllowOverlap = AllowOverlap;
MapEntry->Next = NULL;
//
// Insert the element.
//
PrevEntry = FindPreceedingRegion(BaseOfRegion);
if ( PrevEntry == NULL )
{
//
// Insert at head.
//
MapEntry->Next = m_List;
m_List = MapEntry;
}
else
{
//
// Insert in order.
//
MapEntry->Next = PrevEntry->Next;
PrevEntry->Next = MapEntry;
}
m_RegionCount++;
return MapEntry;
}
HRESULT
MappedMemoryMap::AddRegion(
IN ULONG64 BaseOfRegion,
IN ULONG SizeOfRegion,
IN PVOID Buffer,
IN PVOID UserData,
IN BOOL AllowOverlap
)
{
//
// The region size cannot be zero.
//
if (SizeOfRegion == 0)
{
ErrOut("**** MappedMemoryMap::AddRegion: Empty region being added.\n");
return S_OK;
}
if (IsBadReadPtr(Buffer, SizeOfRegion))
{
ErrOut("**** MappedMemoryMap::AddRegion: Mapping too small to map "
"%s:%X from %p\n", FormatAddr64(BaseOfRegion),
SizeOfRegion, Buffer);
return E_INVALIDARG;
}
ULONG64 EndOfRegion;
PMEMORY_MAP_ENTRY Entry;
ULONG Size;
while (SizeOfRegion > 0)
{
//
// Find the first overlapping region.
// We need to rescan the whole list as it
// may have changed due to insertion of fragments
// of the new region.
//
EndOfRegion = BaseOfRegion + SizeOfRegion;
for (Entry = m_List; Entry != NULL; Entry = Entry->Next)
{
if (EndOfRegion > Entry->BaseOfRegion &&
Entry->BaseOfRegion >= BaseOfRegion)
{
if (AllowOverlap || Entry->AllowOverlap)
{
// Overlap can occur when a stack, ethread or
// eprocess is taken from static data in an image.
// For example, the x86 idle process is static
// data in ntoskrnl. Triage dumps contain the
// eprocess data and it gets mapped and can overlap
// with the ntoskrnl image.
#if 0
WarnOut("WARNING: Allowing overlapped region %s - %s\n",
FormatAddr64(BaseOfRegion),
FormatAddr64(BaseOfRegion + SizeOfRegion - 1));
#endif
Entry = NULL;
}
break;
}
}
if (Entry == NULL ||
BaseOfRegion < Entry->BaseOfRegion)
{
// There's a portion of the beginning of the new
// region which does not overlap so add it and
// trim the description.
Size = Entry == NULL ? SizeOfRegion :
(ULONG)(Entry->BaseOfRegion - BaseOfRegion);
if (!AddMapEntry(BaseOfRegion, Size, Buffer, UserData,
AllowOverlap))
{
return E_OUTOFMEMORY;
}
if (Size == SizeOfRegion)
{
// None of the region overlapped so we're done.
return S_OK;
}
BaseOfRegion += Size;
SizeOfRegion -= Size;
Buffer = (PUCHAR)Buffer + Size;
}
//
// Now handle the overlap.
//
if (SizeOfRegion > Entry->SizeOfRegion)
{
Size = Entry->SizeOfRegion;
}
else
{
Size = SizeOfRegion;
}
int Compare;
__try
{
Compare = memcmp(Buffer, Entry->Region, Size);
}
__except(MappingExceptionFilter(GetExceptionInformation()))
{
return HRESULT_FROM_NT(GetExceptionCode());
}
if (Compare)
{
ErrOut("**** MappedMemoryMap::AddRegion: "
"Conflicting region %s - %s\n",
FormatAddr64(BaseOfRegion),
FormatAddr64(BaseOfRegion + SizeOfRegion - 1));
return HR_REGION_CONFLICT;
}
// Overlap region data matched so it's OK to just
// trim the overlap out of the new region and move
// on to the next possible overlap.
BaseOfRegion += Size;
SizeOfRegion -= Size;
Buffer = (PUCHAR)Buffer + Size;
}
return S_OK;
}
BOOL
MappedMemoryMap::ReadMemory(
IN ULONG64 BaseOfRange,
IN OUT PVOID Buffer,
IN ULONG SizeOfRange,
OUT ULONG * BytesRead
)
/*++
Routine Description:
Read memory from the memory map. ReadMemory can read across regions, as
long as there is no unallocated space between regions.
This routine will do a partial read if the region ends before
SizeOfRange bytes have been read. In that case BytesRead will return the
number of bytes actually read.
Arguments:
BaseOfRange - The base address where we want to read memory from.
SizeOfRange - The length of the region to read memory from.
Buffer - A pointer to a buffer to read memory into.
BytesRead - On success, the number of bytes successfully read.
Return Values:
TRUE - If any number of bytes were successfully read from the memory map.
FALSE - If no bytes were read.
--*/
{
ULONG BytesToReadFromRegion;
PMEMORY_MAP_ENTRY Entry;
ULONG64 BaseToRead;
ULONG SizeToRead;
PBYTE BufferForRead;
ULONG_PTR OffsetToRead;
ULONG AvailSize;
//
// We return TRUE if we read any bytes successfully and FALSE if not.
//
*BytesRead = 0;
BaseToRead = BaseOfRange;
SizeToRead = SizeOfRange;
BufferForRead = (PBYTE) Buffer;
do
{
Entry = FindContainingRegion(BaseToRead);
if ( !Entry )
{
if (*BytesRead)
{
return TRUE;
}
else
{
return FALSE;
}
}
PMEMORY_MAP_ENTRY NextEntry = Entry->Next;
// Due to overlap there may be other entries
// that need to be processed even before the
// end of the containing region.
AvailSize = Entry->SizeOfRegion;
while (NextEntry != NULL)
{
if (NextEntry->BaseOfRegion > BaseToRead)
{
ULONG64 EntryDiff =
NextEntry->BaseOfRegion - Entry->BaseOfRegion;
if (EntryDiff < AvailSize)
{
AvailSize = (ULONG)EntryDiff;
}
break;
}
NextEntry = NextEntry->Next;
}
if (BaseToRead + SizeToRead > Entry->BaseOfRegion + AvailSize)
{
BytesToReadFromRegion = (ULONG)
(Entry->BaseOfRegion - BaseToRead) + AvailSize;
}
else
{
BytesToReadFromRegion = SizeToRead;
}
OffsetToRead = (ULONG_PTR) (BaseToRead - Entry->BaseOfRegion);
__try
{
RtlCopyMemory (BufferForRead,
(PBYTE)Entry->Region + OffsetToRead,
BytesToReadFromRegion
);
}
__except(MappingExceptionFilter(GetExceptionInformation()))
{
return FALSE;
}
*BytesRead += BytesToReadFromRegion;
BaseToRead += BytesToReadFromRegion;
SizeToRead -= BytesToReadFromRegion;
BufferForRead += BytesToReadFromRegion;
} while ( SizeToRead );
return TRUE;
}
BOOL
MappedMemoryMap::GetRegionInfo(
IN ULONG64 Addr,
OUT ULONG64* BaseOfRegion, OPTIONAL
OUT ULONG* SizeOfRegion, OPTIONAL
OUT PVOID* Buffer, OPTIONAL
OUT PVOID* UserData OPTIONAL
)
/*++
Routine Description:
Get information about the region containing the address Addr.
Arguments:
Addr - An address that is contained within some region in the map.
BaseOfRegion - Pointer to a buffer to return the region base.
SizeOfRegion - Pointer to a buffer to retutn the region size.
Buffer - Pointer to a buffer to return the region buffer pointer.
UserData - Pointer to a buffer to return the region client param.
Return Values:
TRUE - On success.
FALSE - On failure.
--*/
{
PMEMORY_MAP_ENTRY Entry;
Entry = FindContainingRegion(Addr);
if ( !Entry )
{
return FALSE;
}
if ( BaseOfRegion )
{
*BaseOfRegion = Entry->BaseOfRegion;
}
if ( SizeOfRegion )
{
*SizeOfRegion = Entry->SizeOfRegion;
}
if ( Buffer )
{
*Buffer = Entry->Region;
}
if ( UserData )
{
*UserData = Entry->UserData;
}
return TRUE;
}
BOOL
MappedMemoryMap::GetNextRegion(
IN ULONG64 Addr,
OUT PULONG64 Next
)
{
PMEMORY_MAP_ENTRY Entry;
Entry = m_List;
while (Entry != NULL)
{
//
// Assuming they're in order.
//
if (Entry->BaseOfRegion > Addr)
{
*Next = Entry->BaseOfRegion;
return TRUE;
}
Entry = Entry->Next;
}
return FALSE;
}
BOOL
MappedMemoryMap::RemoveRegion(
IN ULONG64 BaseOfRegion,
IN ULONG SizeOfRegion
)
{
// XXX drewb - This should carve the given region out of
// any existing regions. Right now we don't need general
// removal functionality though so only handle the case
// where the requested removal is an exact single region
// match.
PMEMORY_MAP_ENTRY PrevEntry;
PMEMORY_MAP_ENTRY Entry;
PrevEntry = FindPreceedingRegion(BaseOfRegion);
if (PrevEntry != NULL)
{
Entry = PrevEntry->Next;
}
else
{
Entry = m_List;
}
if (Entry == NULL)
{
ErrOut("MappedMemoryMap::RemoveRegion NULL region for %s:%x\n",
FormatAddr64(BaseOfRegion), SizeOfRegion);
return FALSE;
}
else if (Entry->BaseOfRegion != BaseOfRegion ||
Entry->SizeOfRegion != SizeOfRegion)
{
ErrOut("MappedMemoryMap::RemoveRegion region mismatch: "
"%s:%x vs. entry %s:%x\n",
FormatAddr64(BaseOfRegion), SizeOfRegion,
FormatAddr64(Entry->BaseOfRegion), Entry->SizeOfRegion);
return FALSE;
}
if (PrevEntry == NULL)
{
m_List = Entry->Next;
}
else
{
PrevEntry->Next = Entry->Next;
}
free(Entry);
m_RegionCount--;
return TRUE;
}
BOOL
MappedMemoryMap::GetRegionByUserData(
IN PVOID UserData,
OUT PULONG64 Base,
OUT PULONG Size
)
{
PMEMORY_MAP_ENTRY Entry;
Entry = m_List;
while (Entry != NULL)
{
if (Entry->UserData == UserData)
{
*Base = Entry->BaseOfRegion;
*Size = Entry->SizeOfRegion;
return TRUE;
}
Entry = Entry->Next;
}
return FALSE;
}
//
// Private functions
//
PMEMORY_MAP_ENTRY
MappedMemoryMap::FindPreceedingRegion(
IN ULONG64 BaseOfRegion
)
{
PMEMORY_MAP_ENTRY PrevEntry;
PMEMORY_MAP_ENTRY Entry;
PrevEntry = NULL;
Entry = m_List;
while (Entry != NULL)
{
//
// Assuming they're in order.
//
if ( Entry->BaseOfRegion >= BaseOfRegion )
{
return PrevEntry;
}
PrevEntry = Entry;
Entry = Entry->Next;
}
return PrevEntry;
}
PMEMORY_MAP_ENTRY
MappedMemoryMap::FindContainingRegion(
IN ULONG64 Addr
)
{
PMEMORY_MAP_ENTRY Entry;
PMEMORY_MAP_ENTRY ReturnEntry = NULL;
Entry = m_List;
//
// We may have overlapping regions, so keep going until we find
// the most precise one (assumed to be the one we care about)
//
while ( Entry != NULL )
{
if ( Entry->BaseOfRegion <= Addr &&
Addr < Entry->BaseOfRegion + Entry->SizeOfRegion)
{
ReturnEntry = Entry;
}
else if (ReturnEntry != NULL &&
Addr >= ReturnEntry->BaseOfRegion + ReturnEntry->SizeOfRegion)
{
// Optimization - we can stop searching if we've already
// found a block and have now left its region. We can't
// stop as long as we're in its region as there may
// be more exact overlaps anywhere within the entire region.
break;
}
Entry = Entry->Next;
}
return ReturnEntry;
}