Windows2000/private/windbg64/debugger/memlist/mm.c
2020-09-30 17:12:32 +02:00

843 lines
19 KiB
C

/*** mm.c - Memory Manager routines and callback routines for cw
* Copyright <C> 1990, Microsoft Corporation
* Purpose: handle the near and far memory requests of dlls, cw and help systems.
* Notes: Include files required for use of the memory manager are:
* #include "cvdef.h"
* #include "mm.h"
* #include "mmproto.h"
* For an example of Memory Manager usage please see testmm.c.
* _bheap_reset is special and assumes Medium > code memory
* model
* There are some CW callback and overridden functions in this
* system. Becareful when making mods to them. See Auxcow.c for
* more information.
*/
#include <windows.h>
#include "cvtypes.h"
#include "mm.h"
#include "mm.hmd"
#include "mm.hpt"
#include "ms.h"
#include <malloc.h> /* for malloc() / free() */
#include <dos.h> // for FP_SEG and FP_OFF
#include <fcntl.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
/* #include "osassert.h" */
#include <assert.h>
#include <memory.h>
#ifdef HOST32
#define _memmax() 100*64L
#endif
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned long ulong;
#ifdef TARGDOS16
unsigned long ulcbDLLBuffer;
#endif // DOS16
#ifndef TARGWIN
#define FHEAPCHK() _fheapchk()
#else // !WIN
#define FHEAPCHK() _HEAPOK
#endif // !WIN
// Handle based allocation table
static MB mbTableInit[ MB_ENTRY_MAX ];
static PMB pmbTable[ MB_TABLE_MAX ] = { mbTableInit };
// Near memory buffer for CW
static unsigned char rgbNearWS[ cbNEARBUFFER ];
static unsigned char * pbNextNearBlock = rgbNearWS;
// Far work space data
#if defined(DOS16)
static unsigned short selBasedHeap[MAXHEAPSELS] = { _NULLSEG, _NULLSEG, _NULLSEG, _NULLSEG, _NULLSEG, _NULLSEG, _NULLSEG };
#endif
#define cbDEFAULTHLPBUF (0x6000) /* default size of help buf */
ulong ucbHelpBuffer = cbDEFAULTHLPBUF;
// Installable Expression evaluator Call Backs only.
/*** MHMemAllocate
* Purpose: To far memory for installable expression evaluators.
* Input:
* cb The number of bytes to allocate
* Output:
* Returns:
* A far pointer to the memory allocated
* Exceptions:
* Notes: This is a thunk to the CodeView Memory manager
*/
HDEP LOADDS PASCAL
MHMemAllocate ( size_t cb )
{
return ( MMhAllocMb ( (USHORT) MMDLLHEAP, (UCHAR) FMALLOCED, (USHORT) cb ) );
}
/*** MHIsMemLocked
* Purpose: To check to see if memory is locked
* Input:
* hMem - A handle to the memory
* Output:
* Returns:
* True if memory is locked
* Exceptions:
* Notes:
*/
SHFLAG LOADDS PASCAL
MHIsMemLocked ( HDEP hmem )
{
return ( MMcbGetLockFromMb ( hmem ) );
}
/*** MHMemFree
* Purpose: To free memory previously allocated with MHAllocate
* Input:
* hMem - A handle of the memory to free
* Output:
* Returns:
* Exceptions:
* Notes:
* If an invalid memory pointer is passed to be freed, unexpected
* results may occur
*/
void LOADDS PASCAL
MHMemFree ( HDEP hmem )
{
MMDeallocMb ( hmem );
}
/*** MHMemReAlloc
* Purpose: To reallocate some memory
* Input:
* hMem - A handle to the old memory to reallocate
* cbNew - The new size
* Output:
* Returns:
* - A new handle to the newly allocated memory. Or a NULL on error.
* If an error ocurred, the old handle is still valid, otherwise
* the old handle is invalid.
* Exceptions:
* Notes:
* For this to work, the memory must not be locked!!
* If a larger block is requested, the extended memory has
* uninitialized data in it.
*/
HDEP LOADDS PASCAL
MHMemReAlloc( HDEP hmem, size_t cbNew )
{
return ( MMhReallocMb ( hmem, cbNew, 0 ) );
}
/*** MHMemLock
* Purpose: To lock into physical memory allocated by MHMemAllocate
* Input:
* hMem - A handle to the memory
* Output:
* Returns:
* The physical memory address
* Exceptions:
* Notes: This is a IEE callback function
*/
HVOID LOADDS PASCAL
MHMemLock( HDEP hmem )
{
return ( MMlpvLockMb ( hmem ) );
}
/*** MHMemUnLock
* Purpose: To unlock memory previously lock by MHMemLock
* Input:
* hMem
* Output:
* Returns:
* Exceptions:
* Notes:
* This is a IEE callback only
*/
void LOADDS PASCAL
MHMemUnLock ( HDEP hmem )
{
MMbUnlockMb ( hmem );
}
// General Exported Far Memory Manager
/*** MHwInit - Initialize a block of far memory to use during codeview.
* Purpose: To set up a block of far memory for CW, HELP, IEE, OSDebug
* systems to use as well (in dos).
* Input: none.
* Output: none.
* Notes: This routine can cause codeview to exit if cbFWORKMIN bytes
* of memory is not available.
* This routine sets up the space (in dos3) for SBAlloc, etc.,
* to use if necessary. It also sets up the initial SB table
* and the SB pointer table.
*/
unsigned short PASCAL
MMwInit () {
unsigned short i;
unsigned short retval = TRUE;
#if defined(DOS16)
long cbHeap;
static unsigned short cselAllocated;
selBasedHeap[ MMEMERGENCYHEAP ] = bselAlloc ( &i, cbFWORKMIN );
if ( i < cbFWORKMIN ) {
retval = FALSE;
}
else {
cselAllocated = MMCOWHEAP;
selBasedHeap[ MMCOWHEAP ] = bselAlloc ( &i, cbFWORKSTART );
if ( i < cbFWORKMIN ) {
retval = FALSE;
}
else {
cselAllocated++;
cbHeap = ulcbDLLBuffer;
for ( cselAllocated;
cselAllocated < cHEAPSEL && cbHeap;
cselAllocated++ ) {
ushort cbThisAlloc = 0;
selBasedHeap[ cselAllocated ] = bselAlloc ( &cbThisAlloc, cbHeap );
cbHeap -= cbThisAlloc;
}
cbHeap = ucbHelpBuffer;
for ( cselAllocated;
cselAllocated < cHEAPSEL && cbHeap;
cselAllocated++ ) {
ushort cbThisAlloc = 0;
selBasedHeap[ cselAllocated ] = bselAlloc ( &cbThisAlloc, cbHeap );
cbHeap -= cbThisAlloc;
}
}
}
#endif
// initialize the sb manager table
for ( i = 1; i < MB_TABLE_MAX; i++ ) {
pmbTable[ i ] = NULL;
}
for ( i = 0; i < MB_ENTRY_MAX; i++ ) {
mbTableInit[ i ].flags = MBUNDEFINED;
mbTableInit[ i ].cb = 0;
mbTableInit[ i ].lpvBlock = NULL;
}
return retval;
}
/*** MMlpvAlloc - CV API callback for far memory buffer handling
* Purpose: To allocate far memory for CW, CV, DLLs, IEE, and the Help
* system (dos only)
* Input: unsigned short wPriority level of priority required for memory request.
* unsigned short cb, count of bytes requested.
* Output:
* Returns far pointer to block if successful, NULL if not.
* Exceptions:
* Notes:
*/
void FAR * FAR PASCAL
MMlpvAlloc( unsigned short wPriority, unsigned short cb) {
void FAR * lpv = NULL;
#if defined(DOS16)
unsigned short i;
for ( i = wPriority; i < cHEAPSEL; i++) {
if ( selBasedHeap[ i ] != _NULLSEG ) {
unsigned uOff = (unsigned )_bmalloc ( selBasedHeap[ i] , cb );
assert ( (_bheapset( selBasedHeap[i],0xff ) == _HEAPOK) || (_bheapset( selBasedHeap[i],0xff ) == _HEAPEMPTY) );
if ( uOff != (unsigned) _NULLOFF) {
FP_OFF ( lpv ) = uOff;
FP_SEG ( lpv ) = selBasedHeap[ i ];
assert ( (_bheapset( selBasedHeap[i],0xff ) == _HEAPOK) );
break;
}
}
}
#else // DOS3
#ifdef HOST32
assert ( _heapchk ( ) == _HEAPOK );
lpv = malloc( cb );
#else
assert ( FHEAPCHK() == _HEAPOK );
lpv = _fmalloc( cb );
#endif // HOST32
#endif // DOS3
return lpv;
}
/*** MMFreeLpv - CV API for far memory buffer handling free of lpv alloc
* Purpose: To free a far work buffer
* Input: void far * lpv, far pointer to block to deallocate
* Notes: Since all blocks are allocated with only an offset, we just
* have to match that offset value with the value in the
* allocation table, fmb.fws.
*/
void FAR PASCAL
MMFreeLpv( void FAR * lpv)
{
#if defined(DOS16)
int FAR _cdecl _bheap_reset ( unsigned );
_bfree( FP_SEG(lpv), FP_OFF(lpv));
// _bheap_reset is NOT a part of the standard c6 runtime...
// supplied to reduce fragmentation, it resets the rover ptr to
// the first free block in the based heap.
_bheap_reset ( FP_SEG(lpv) );
assert ( (_bheapset( FP_SEG(lpv),0xff ) == _HEAPOK) || (_bheapset( FP_SEG(lpv), 0xff ) == _HEAPEMPTY) );
#else // dos5
#ifdef HOST32
assert ( _heapchk ( ) == _HEAPOK );
free ( lpv );
#else
assert ( FHEAPCHK ( ) == _HEAPOK );
_ffree( lpv );
#endif
#endif
}
/*** MMhAllocMb - Allocate handle based memory
* Purpose: To allocate cb bytes of memory and return a handle to that
* memory.
* Input: cb, count of bytes
* Returns: handle to memory if successful, MBUNDEFINED if not.
* Note: This routine can also allocate near memory when the parameter
* wWhere is set to MALLOCED. Currently, GlobalAlloc and
* GlobalRealloc use this method, so that the listbox.c will
* grab near memory first. This is not detrimental, since it
* will not generally use too much and most dialogs have no
* need for near memory. Three exceptions come to mind:
* Breakpoints, watches, and quickwatch dialogs. Hence,
* before a near malloc is done, the amount of free near
* memory is checked so that some room is left. See the
* enum cbNEARLEAVEFREE.
*/
HDEP PASCAL FAR
MMhAllocMb(
unsigned short wPriority,
unsigned char bWhere,
unsigned short cb
)
{
register unsigned short i = 0;
register unsigned short j = MB_ENTRY_MAX;
MBH mbhRet;
// first of all, find where a sb entry is, and then an entry in that one.
mbhRet.hmem = MBUNDEFINED;
while ( (j == MB_ENTRY_MAX) &&
(i < MB_TABLE_MAX) &&
(pmbTable[ i ] != NULL) ) {
PMB pmb = pmbTable[ i ];
for ( j = 0; j < MB_ENTRY_MAX; j++, pmb++ ) {
if ( pmb->flags == MBUNDEFINED ) {
// found a free handle
break;
}
}
if ( j == MB_ENTRY_MAX ) { // none found, go to next mb.
i++;
}
}
// at this point, i and j are VERY interesting. if i == MB_TABLE_MAX,
// then we are SOL, no sb room is available. Otherwise,
// everything is ok, i will have the sb table index, and j
// will have the sb entry index.
if ( i < MB_TABLE_MAX ) {
if ( pmbTable[ i ] == NULL ) { // allocate a new sb table
pmbTable[ i ] = MMlpvAlloc ( wPriority, sizeof( MB ) * MB_ENTRY_MAX );
j = 0;
if ( pmbTable[ i ] != NULL ) {
// initialize the sb table
unsigned short ind;
PMB pmb = pmbTable[ i ];
for ( ind = 0; ind < MB_ENTRY_MAX; ind++, pmb++ ) {
pmb->flags = MBUNDEFINED;
pmb->cb = 0;
pmb->lpvBlock = NULL;
pmb->swLocked = -1;
}
}
}
if ( pmbTable[ i ] != NULL ) {
PMB pmb = pmbTable[ i ];
pmb += j;
// try in near if bWhere == MALLOCED and
// the biggest block is at least as big as cb + cbNEARLEAVEFREE
#ifndef TARGWIN
if ( bWhere == MALLOCED && cb + cbNEARLEAVEFREE < _memmax() ){
void * p = malloc ( cb );
if ( p != NULL ) {
pmb->lpvBlock = (void FAR *) p;
pmb->cb = cb;
pmb->swLocked = 0;
mbhRet.mbhi.mbNum = (uchar) i;
mbhRet.mbhi.index = (uchar) j;
mbhRet.mbhi.flags = pmb->flags = bWhere;
}
}
#else // !TARGWIN
if ( bWhere == MALLOCED ){
void * p = malloc ( cb );
if ( p != NULL ) {
pmb->lpvBlock = (void FAR *) p;
pmb->cb = cb;
pmb->swLocked = 0;
mbhRet.mbhi.mbNum = (uchar) i;
mbhRet.mbhi.index = (uchar) j;
mbhRet.mbhi.flags = pmb->flags = bWhere;
}
}
#endif // !TARGWIN
if ( pmb->lpvBlock == NULL ) {
if ( (pmb->lpvBlock = MMlpvAlloc ( wPriority, cb )) != NULL ) {
pmb->cb = cb;
pmb->swLocked = 0;
mbhRet.mbhi.mbNum = (uchar) i;
mbhRet.mbhi.index = (uchar) j;
mbhRet.mbhi.flags = pmb->flags = FMALLOCED;
}
else {
pmb->flags = MBUNDEFINED;
pmb->swLocked = -1;
pmb->cb = 0;
}
}
}
}
return ( mbhRet.hmem );
}
/*** MMDeallocMb - Deallocate handle based memory
* Purpose: To deallocate memory allocated using SBAlloc.
* Input: h, handle to memory
*/
void PASCAL FAR
MMDeallocMb ( HDEP hmem )
{
PMB pmb = PmbHmemToPmb ( hmem );
if ( pmb != NULL ) {
if ( pmb->flags == MALLOCED ) {
free ( (void *) (pmb->lpvBlock) );
}
else {
MMFreeLpv ( pmb->lpvBlock );
}
pmb->flags = MBUNDEFINED;
pmb->cb = 0;
pmb->lpvBlock = NULL;
}
}
/*** MMlpvHandleToLp - map SB handle to far *
* Purpose: To dereference an sb handle to a far *
* Input: h, handle
* Returns: far * if successful, NULL if not.
*/
void FAR * PASCAL FAR
MMlpvHandleToLp ( HDEP hmem )
{
PMB pmb;
void FAR * retval = NULL;
if ( ( pmb = PmbHmemToPmb ( hmem ) ) != NULL ) {
retval = pmb->lpvBlock;
}
return retval;
}
/*** MMlpvLockMb - map MB handle to far *
* Purpose: To dereference an sb handle to a far *
* Input: wHandle, handle
* Returns: far * if successful, NULL if not.
*/
void FAR * FAR PASCAL
MMlpvLockMb (HDEP hmem )
{
PMB pmb;
pmb = PmbHmemToPmb ( hmem );
assert ( pmb != NULL );
assert ( pmb->swLocked >= 0 );
pmb->swLocked++;
return ( MMlpvHandleToLp ( hmem ) );
}
/*** MMbUnlockMb - Decrement Lock count
* Purpose: To decrement the lock count on MB block given a handle.
* This function will decrement the internal counter
* Input: h, handle
* Returns: far * if successful, NULL if not.
*/
unsigned short FAR PASCAL
MMbUnlockMb ( HDEP hmem )
{
PMB pmb = PmbHmemToPmb ( hmem );
assert ( pmb != NULL );
assert ( pmb->swLocked > 0 );
pmb->swLocked--;
return ((pmb->swLocked > 0 ));
}
/*** MMwHandleSize - Get size of block of memory from handle.
* Purpose: To get the size of the block of memory referenced by a
* MBH handle.
* Input: h, handle
* Returns: cb of the block if successful, 0 if not.
*/
unsigned short PASCAL FAR
MMwHandleSize ( HDEP hmem )
{
PMB pmb;
unsigned short retval = 0;
if ( ( pmb = PmbHmemToPmb ( hmem ) ) != NULL ) {
retval = pmb->cb;
}
return retval;
}
/*** MMhReallocMb (wHandle, cb, flags)
*Purpose:
* Realloc a handle to far memory.
*Entry:
* wHandle Handle to far memory.
* cb Number of bytes to reallocate to.
* flags Unused parameter.
*Exit:
* Returns reallocated handle if successful, NULL if not.
*Exceptions:
* None.
*/
HDEP FAR PASCAL
MMhReallocMb (
HDEP hmem,
unsigned long cb,
unsigned short flags )
{
unsigned short cbMove;
unsigned char FAR * lpDst = NULL;
unsigned char FAR * lpSrc = NULL;
PMB pmb = NULL;
Unreferenced ( cbMove );
Unreferenced ( flags );
// Try near memory first.
// only allow reallocations to be < 65520 bytes.
#if defined(DOS16)
if ( cb <= 0xfff0 ) {
if ( ( lpSrc = MMlpvHandleToLp ( hmem ) ) != NULL ) {
lpDst = MMlpvAlloc ( MMDLLHEAP, (unsigned short) cb );
if ( lpDst != NULL ) {
pmb = PmbHmemToPmb ( hmem );
assert ( pmb != NULL );
cbMove = MMwHandleSize ( hmem ); // size of original handle
_fmemcpy ( lpDst, lpSrc, min ( cbMove, (unsigned) cb ));
MMFreeLpv ( lpSrc );
pmb->lpvBlock = lpDst;
pmb->cb = (unsigned short) cb;
}
else {
pmb->lpvBlock = NULL;
pmb->cb = 0;
pmb->flags = MBUNDEFINED;
hmem = MBUNDEFINED;
}
}
}
#else
pmb = PmbHmemToPmb ( hmem );
assert ( pmb != NULL );
#ifdef HOST32
assert ( _heapchk ( ) == _HEAPOK );
lpSrc = realloc ( MMlpvHandleToLp ( hmem ), (unsigned short) cb );
#else
assert ( FHEAPCHK( ) == _HEAPOK );
lpSrc = _frealloc ( MMlpvHandleToLp ( hmem ), (unsigned short) cb );
#endif
if ( lpSrc != NULL ) {
pmb->lpvBlock = lpSrc;
pmb->cb = (unsigned short) cb;
}
else {
pmb->lpvBlock = NULL;
pmb->cb = 0;
pmb->flags = MBUNDEFINED;
}
#endif
return hmem;
}
/*** MHOutOfMemory - general purpose for CW out of memory conditions.
*/
void FAR PASCAL MMOutOfMemory()
{
CVMessage ( ERRORMSG, ENOMEM, MSGBOX );
}
/*** MMcbGetLockFromMb
* Purpose: To check to see if memory is locked
* Input:
* hMem - A handle to the memory
* Output:
* Returns:
* True if memory is locked
* Exceptions:
* Notes:
*/
unsigned short FAR PASCAL
MMcbGetLockFromMb (HDEP hmem )
{
PMB pmb;
pmb = PmbHmemToPmb ( hmem );
assert ( pmb != NULL );
return (pmb->swLocked );
}
// Local Functions
#if defined(DOS16)
/*** bselAlloc - to allocate a block of memory via _bheapseg
* Purpose: to allocate memory blocks for dos3 static CW and help buffers.
* Input: cbAllocated, where to place the amount actually allocated.
* cbHeapSize, amount to allocate
* Output: cbAllocated, amount actually allocated
* Returns: selector of block allocated.
* Exceptions:
* Notes:
*/
LOCAL ushort PASCAL
bselAlloc ( ushort * cbAllocated, long cbHeapSize ) {
ushort retval = _NULLSEG;
long cbThisAlloc;
if ( cbHeapSize > 0 ) {
assert ( cbHeapSize <= ( (long)_HEAP_MAXREQ << 1 ) );
if ( cbHeapSize > _HEAP_MAXREQ ) {
cbHeapSize >= 1;
}
cbThisAlloc = cbHeapSize;
while ( (retval = _bheapseg ( (unsigned short)cbThisAlloc )) == _NULLSEG ) {
// failed, decrease request down by cbFWORKGRAN until we
// hit 0
cbThisAlloc -= cbFWORKGRAN;
if ( cbThisAlloc < 0 ) {
cbThisAlloc = 0;
break;
}
}
*cbAllocated = (ushort) cbThisAlloc;
}
return retval;
}
#endif
/*** PmbHmemToPmb - return a pointer to the sb refered to by a handle
* Input: h, sb handle
* Returns: pmb, pointer to the sb
* Exceptions:
* Notes:
*/
LOCAL PMB PASCAL NEAR
PmbHmemToPmb ( HDEP hmem )
{
register MBH mbh;
register unsigned short j;
PMB pmbRet = NULL;
if ( hmem != MBUNDEFINED ) {
mbh.hmem = hmem;
j = mbh.mbhi.mbNum;
if ( j < MB_TABLE_MAX && pmbTable[ j ] != NULL ) {
PMB pmb = pmbTable[ j ];
j = mbh.mbhi.index;
if ( pmb[ j ].flags != MBUNDEFINED && pmb[ j ].lpvBlock != NULL ) {
pmbRet = &pmb[ j ];
}
}
}
return pmbRet;
}