📄 fastmm4bcb.cpp.svn-base
字号:
/*
Fast Memory Manager: BCB support 2.0
Description:
FastMM support unit for BCB6 1.0. Loads FastMM4 on startup of the Borland C++
Builder application or DLL.
Usage:
1) Under the Project -> Options -> Linker menu uncheck "Use Dynamic RTL"
(sorry, won't work with the RTL DLL).
2) Add FastMM4.pas to your project and build it so that FastMM4.hpp is
created.
3) Add FastMM4BCB.cpp to your project.
FastMM will now install itself on startup and replace the RTL memory manager.
Acknowledgements:
- Jarek Karciarz, Vladimir Ulchenko (Vavan) and Bob Gonder for their help in
implementing the initial BCB support.
- JiYuan Xie for doing an entire rewrite of this unit to allow leak reporting,
etc. under BCB.
Change log:
Version 1.00 (15 June 2005):
- Initial release. Due to limitations of BCB it cannot be uninstalled (thus
no leak checking and not useable in DLLs unless the DLL always shares the
main application's MM). Thanks to Jarek Karciarz, Vladimir Ulchenko and Bob
Gonder for their help.
Version 1.01 (6 August 2005):
- Fixed a regression bug (Thanks to Omar Zelaya).
Version 2.00 (22 April 2008):
- Rewritten by JiYuan Xie to implement leak reporting, etc. (Thank you!)
*/
//#ifndef _NO_VCL
#pragma hdrstop
#include "FastMM4Messages.hpp"
#include "FastMM4.hpp"
#pragma option push
#pragma option -k- -d -vi- -O2 -b- -3 -a8 -pc -RT- -x -xd -r -AT -vG- -vG0- -vG1- -vG2- -vG3- -vGc- -vGt- -vGd-
#ifdef __cplusplus
extern "C" {
#endif
#ifdef PatchBCBTerminate
#ifdef FullDebugMode
#ifndef LoadDebugDLLDynamically
#pragma link "FastMM_FullDebugMode.lib"
#if defined(RawStackTraces)
__declspec(dllimport) void __fastcall GetRawStackTrace(unsigned * AReturnAddresses,
unsigned AMaxDepth, unsigned ASkipFrames);
#else
__declspec(dllimport) void __fastcall GetFrameBasedStackTrace(unsigned * AReturnAddresses,
unsigned AMaxDepth, unsigned ASkipFrames);
#endif
__declspec(dllimport) void __fastcall LogStackTrace(unsigned * AReturnAddresses,
unsigned AMaxDepth, char *ABuffer);
#endif
#endif
#pragma pack(push,1)
typedef struct {
unsigned char JmpInst; //E9
int Offset;
} TRelativeJmp32, * PRelativeJmp32;
typedef struct {
unsigned short JmpInst; //FF 25
void * * DestPtr;
} TIndirectJmp32, * PIndirectJmp32;
#pragma pack(pop)
//Return true if write OK
bool __fastcall WriteMem(void * Location, void * Data, unsigned int DataSize)
{
unsigned long OldProtect;
if (VirtualProtect(Location, DataSize, PAGE_EXECUTE_READWRITE, &OldProtect))
{
memmove(Location, Data, DataSize);
FlushInstructionCache(GetCurrentProcess(), Location, sizeof(DataSize));
VirtualProtect(Location, DataSize, OldProtect, &OldProtect);
return true;
}
else {
return false;
}
}
#define RelativeJmp32Inst (0xE9)
//Return true if patch OK
bool __fastcall PatchProc(void * OldProc, void * NewProc, TRelativeJmp32 * Backup)
{
if (OldProc && NewProc)
{
TRelativeJmp32 JmpData;
JmpData.JmpInst = RelativeJmp32Inst;
JmpData.Offset = (int)NewProc - ((int)OldProc + sizeof(JmpData));
if (Backup)
{
*Backup = *((PRelativeJmp32)OldProc);
}
return WriteMem(OldProc, &JmpData, sizeof(JmpData));
}
else {
return false;
}
};
//Return true if unpatch OK
bool __fastcall UnPatchProc(void * OldProc, void * NewProc, TRelativeJmp32 * Backup)
{
if (OldProc && NewProc && Backup)
{
int Offset = (int)NewProc - ((int)OldProc + sizeof(TRelativeJmp32));
if ((((PRelativeJmp32)OldProc)->JmpInst == RelativeJmp32Inst)
&& (((PRelativeJmp32)OldProc)->Offset == Offset))
{
return WriteMem(OldProc, &Backup, sizeof(*Backup));
}
}
return false;
};
#ifndef _RTLDLL //Not using Dynamic RTL
extern void _terminate(int code);
#endif
#ifndef FullDebugMode
#define InternalGetMem FastGetMem
#define InternalFreeMem FastFreeMem
#define InternalReallocMem FastReallocMem
#if __BORLANDC__ >= 0x582
//>= BDS2006 ?
#define InternalAllocMem FastAllocMem
#endif
#else
#define InternalGetMem DebugGetMem
#define InternalFreeMem DebugFreeMem
#define InternalReallocMem DebugReallocMem
#if __BORLANDC__ >= 0x582
//>= BDS2006 ?
#define InternalAllocMem DebugAllocMem
#endif
#endif //FullDebugMode
#ifdef CheckCppObjectTypeEnabled
void __fastcall FinalizeModuleCodeDataRanges(void);
#endif
void __fastcall FinalizeHeapRedirectorStoreList(void);
extern bool IsBorlandMMDLL;
#if defined(__DLL__) && defined(FullDebugMode) && defined(LoadDebugDLLDynamically)
void __fastcall CallOldFullDebugModeDllEntry(void);
#endif
void * StockGetMemPtr = NULL;
void New_terminate(int code)
{
//FasttMM4.pas need export a "FinalizeMemoryManager" routine which contain
//codes of original "finalization" section
FinalizeMemoryManager();
#ifdef CheckCppObjectTypeEnabled
GetCppVirtObjSizeByTypeIdPtrFunc = NULL;
GetCppVirtObjTypeIdPtrFunc = NULL;
GetCppVirtObjTypeNameFunc = NULL;
GetCppVirtObjTypeNameByTypeIdPtrFunc = NULL;
GetCppVirtObjTypeNameByVTablePtrFunc = NULL;
FinalizeModuleCodeDataRanges();
#endif
#ifdef DetectMMOperationsAfterUninstall
//Do nothing
#endif
if (IsBorlandMMDLL)
{
FinalizeHeapRedirectorStoreList();
}
#if defined(__DLL__) && defined(FullDebugMode) && defined(LoadDebugDLLDynamically)
CallOldFullDebugModeDllEntry();
#endif
ExitProcess(code);
}
void * PatchLocation = NULL;
#if defined(__DLL__) && defined(FullDebugMode) && defined(LoadDebugDLLDynamically)
#pragma pack(push,1)
typedef struct {
unsigned char PushEbp; //0x55
unsigned short MovEbpEsp; //0x8B 0xEC
unsigned char SubEsp[3]; //0x83 0xC4 0xC4
} DelphiDllEntryInsts, *DelphiDllEntryInstsPtr;
typedef struct {
DelphiDllEntryInsts OldInsts;
TRelativeJmp32 JmpToRemainInsts;
} FullDebugModeDllEntryThunk;
#pragma pack(pop)
FullDebugModeDllEntryThunk OldFullDebugModeDllEntryThunk;
bool ExecuteOldFullDebugModeDllEntry = false;
bool FullDebugModeDllEntryHooked = false;
bool __fastcall PrepareFullDebugModeDllEntryThunk(FullDebugModeDllEntryThunk *Thunk,
void *OldEntry)
{
DelphiDllEntryInstsPtr OldInstsPtr = (DelphiDllEntryInstsPtr)OldEntry;
if ((OldInstsPtr->PushEbp == 0x55)
&& (OldInstsPtr->MovEbpEsp == 0xEC8B)
&& (OldInstsPtr->SubEsp[0] == 0x83)
&& (OldInstsPtr->SubEsp[1] == 0xC4))
{
unsigned long OldProtect;
if (VirtualProtect((void *)Thunk, sizeof(*Thunk), PAGE_EXECUTE_READWRITE, &OldProtect))
{
Thunk->OldInsts = *OldInstsPtr;
//jump to (OldEntry + sizeof(*OldInstsPtr)) from Thunk->JmpToRemainInsts
Thunk->JmpToRemainInsts.JmpInst = RelativeJmp32Inst;
Thunk->JmpToRemainInsts.Offset = ((int)OldInstsPtr + sizeof(*OldInstsPtr))
- ((int)&Thunk->JmpToRemainInsts + sizeof(Thunk->JmpToRemainInsts));
return true;
}
}
return false;
}
//#pragma warn -8070 //"W8070 Function should return a value"
#pragma option -w-rvl //the same as above
__declspec(naked) BOOL WINAPI NewFullDebugModeDllEntry(
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
//[ESP + 4] hinstDLL
//[ESP + 8] fdwReason
//[ESP + 12] lpvReserved
//if (fdwReason != DLL_PROCESS_DETACH)
//return OldFullDebugModeEntry(hinstDLL, fdwReason, lpvReserved);
//else
//return true;
asm
{
mov eax, [esp + 8] //fdwReason
test eax, eax //is DLL_PROCESS_DETACH ?
jz ProcessDetech
jmp OldFullDebugModeDllEntryThunk //not DLL_PROCESS_DETACH, call original entry
ProcessDetech:
movzx eax, ExecuteOldFullDebugModeDllEntry
test eax, eax
jz Exit //do nothing if ExecuteOldFullDebugModeDllEntry flag not set
xor eax, eax
mov ExecuteOldFullDebugModeDllEntry, al //reset ExecuteOldDebugModeDllEntry flag
jmp OldFullDebugModeDllEntryThunk
Exit:
setz al
ret
}
}
void * __fastcall GetModuleEntryPoint(HMODULE AModule)
{
if (AModule)
{
PIMAGE_NT_HEADERS ntheader = (PIMAGE_NT_HEADERS)((unsigned)AModule
+ ((PIMAGE_DOS_HEADER)AModule)->e_lfanew);
return (void *)(ntheader->OptionalHeader.AddressOfEntryPoint
+ (unsigned)AModule);
}
else
{
return NULL;
}
}
bool __fastcall TryHookFullDebugModeDllEntry(void)
{
HMODULE AModule = GetModuleHandle(FullDebugModeLibraryName);
if (AModule)
{
void *Entry = GetModuleEntryPoint(AModule);
if (Entry)
{
if (PrepareFullDebugModeDllEntryThunk(&OldFullDebugModeDllEntryThunk, Entry))
{
FullDebugModeDllEntryHooked = PatchProc(Entry, &NewFullDebugModeDllEntry, NULL);
return FullDebugModeDllEntryHooked;
}
}
}
return false;
}
void __fastcall CallOldFullDebugModeDllEntry(void)
{
if (FullDebugModeDllEntryHooked)
{
HMODULE AModule = GetModuleHandle(FullDebugModeLibraryName);
if (AModule)
{
ExecuteOldFullDebugModeDllEntry = 1;
NewFullDebugModeDllEntry((HINSTANCE)AModule, DLL_PROCESS_DETACH, NULL);
}
}
}
#endif
#define DVCLALResName "DVCLAL"
#define _terminateExport "_terminate"
//Return true if patched OK
bool __fastcall Patch_terminate(void)
{
if (!PatchLocation)
{
#ifndef _RTLDLL //Not uses Dynamic RTL
PatchLocation = &_terminate;
#else
//Get module handle of RTL dll
PIndirectJmp32 P = (PIndirectJmp32)&exit;
if ((!IsBadReadPtr(P, sizeof(TIndirectJmp32))) && (P->JmpInst == 0x25FF)
&& (P->DestPtr) && (!IsBadReadPtr(P->DestPtr, sizeof(void *))))
{
PatchLocation = *(P->DestPtr);
}
else {
PatchLocation = P;
}
PatchLocation = (void *)System::FindHInstance(PatchLocation);
if (PatchLocation)
{
//Get real patch location
PatchLocation = GetProcAddress((HMODULE)PatchLocation, _terminateExport);
if (!PatchLocation)
{
return false;
}
}
else {
return false;
}
#endif //_RTLDLL
if ((((PRelativeJmp32)PatchLocation)->JmpInst == RelativeJmp32Inst)
|| (!PatchProc(PatchLocation, &New_terminate, NULL)))
{
PatchLocation = NULL;
return false;
}
else {
return true;
}
}
else {
return true;
}
}
extern int __CPPdebugHook;
bool IsMMInstalled = false;
bool IsInDLL = false;
bool IsBorlandMMDLL = false;
bool terminatePatched = false;
#define CPPdebugHookExport "___CPPdebugHook"
//#ifndef _RTLDLL
//#pragma warn -8070 //"W8070 Function should return a value"
#pragma option -w-rvl //the same as above
__declspec(naked) void * _RTLENTRY Cpp_malloc_Stub(size_t size)
{
//if (size)
//return InternalGetMem(size);
//else
//return NULL;
asm
{
mov eax, [esp + 4] //size
test eax, eax
jz Exit
#if __BORLANDC__ >= 0x564
jmp InternalGetMem
nop
#else
call InternalGetMem
ret
#endif
nop
nop
Exit:
ret
}
}
__declspec(naked) void _RTLENTRY Cpp_free_Stub(void *block)
{
//if (block)
//InternalFreeMem(block);
asm
{
mov eax, [esp + 4] //block
test eax, eax
jz Exit
#if __BORLANDC__ >= 0x564
jmp InternalFreeMem
nop
#else
call InternalFreeMem
ret
#endif
nop
nop
Exit:
ret
}
}
__declspec(naked) void * _RTLENTRY Cpp_realloc_Stub(void *block, size_t size)
{
/*
if (!block)
{
if (size)
return InternalGetMem(size);
else
return NULL;
}
else {
if (!size)
{
InternalFreeMem(block);
return NULL;
}
else
return InternalReallocMem(block, size);
}
*/
asm
{
mov eax, [esp + 4] //block
test eax, eax
jnz Realloc
Alloc:
mov eax, [esp + 8] //size
test eax, eax
jz Exit2 //Exit1
#if __BORLANDC__ >= 0x564
jmp InternalGetMem
nop
#else
call InternalGetMem
ret
#endif
nop
nop
//Exit1:
//ret
Realloc:
mov edx, [esp + 8] //size
test edx, edx
jnz DoRealloc
call InternalFreeMem
ReturnNULL:
xor eax, eax
Exit2:
ret
DoRealloc:
#if __BORLANDC__ >= 0x564
jmp InternalReallocMem
//ret
#else
call InternalReallocMem
ret
#endif
}
}
__declspec(naked) void _RTLENTRY Cpp_terminate_Stub(void)
{
//Do nothing
asm ret;
}
#ifdef DetectMMOperationsAfterUninstall
typedef void * (__fastcall * GetMemFunc)(int Size);
typedef int (__fastcall * FreeMemFunc)(void * P);
typedef void * (__fastcall * ReallocMemFunc)(void * P, int Size);
#if __BORLANDC__ >= 0x582
//>= BDS2006 ?
typedef void * (__fastcall * AllocMemFunc)(unsigned Size);
#endif
GetMemFunc InvalidGetMemPtr;
FreeMemFunc InvalidFreeMemPtr;
ReallocMemFunc InvalidReallocMemPtr;
__declspec(naked) void * _RTLENTRY Cpp_Invalid_malloc_Stub(size_t size)
{
asm
{
mov eax, [esp + 4] //size
test eax, eax
jz Exit
#if __BORLANDC__ >= 0x564
jmp InvalidGetMemPtr
nop
#else
call InvalidGetMemPtr
ret
#endif
nop
Exit:
ret
}
}
__declspec(naked) void _RTLENTRY Cpp_Invalid_free_Stub(void *block)
{
asm
{
mov eax, [esp + 4] //block
test eax, eax
jz Exit
#if __BORLANDC__ >= 0x564
jmp InvalidFreeMemPtr
nop
#else
call InvalidFreeMemPtr
ret
#endif
nop
Exit:
ret
}
}
__declspec(naked) void * _RTLENTRY Cpp_Invalid_realloc_Stub(void *block, size_t size)
{
asm
{
mov eax, [esp + 4] //block
test eax, eax
jnz Realloc
Alloc:
mov eax, [esp + 8] //size
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -