mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-29 12:35:53 +01:00
389 lines
9.5 KiB
C++
389 lines
9.5 KiB
C++
/*
|
|
* MemoryTracker.cpp
|
|
*
|
|
* Created on: Nov 9, 2023
|
|
* Author: jief
|
|
*/
|
|
|
|
#include <Platform.h>
|
|
|
|
#include "MemoryTracker.h"
|
|
#include "../cpp_foundation/XString.h"
|
|
|
|
#ifndef DEBUG_ALL
|
|
#define DEBUG_MT 1
|
|
#else
|
|
#define DEBUG_MT DEBUG_ALL
|
|
#endif
|
|
|
|
#if DEBUG_MT == 0
|
|
#define DBG(...)
|
|
#else
|
|
#define DBG(...) DebugLog(DEBUG_MT, __VA_ARGS__)
|
|
#endif
|
|
|
|
#ifdef MEMORY_TRACKER_ENABLED
|
|
|
|
#define MAGIC_BEGINNING 0xDEADBEEFBBBBBBBB
|
|
#define MAGIC_END 0xEEEEEEEEDEADBEEF
|
|
|
|
|
|
uint64_t MT_alloc_count = 0;
|
|
bool MT_recording = false;
|
|
uint64_t MT_count_to_break_into = 0;
|
|
bool MT_report_deleting_non_recoded_ptr = false;
|
|
|
|
MTArray<uintptr_t> allocatedPtrArray;
|
|
MTArray<uint64_t> allocatedPtrInfoArray;
|
|
|
|
#if defined(IS_UEFI_MODULE)
|
|
void* real_malloc(EFI_MEMORY_TYPE MemoryType, size_t size);
|
|
#define _real_malloc(MemoryType, size) real_malloc(MemoryType, size)
|
|
#else
|
|
#define _real_malloc(MemoryType, size) real_malloc(size)
|
|
#endif
|
|
void* real_malloc(size_t size);
|
|
void real_free(void*);
|
|
|
|
|
|
|
|
void MT_import(const void* p)
|
|
{
|
|
// printf("MT_import ptr %llx\n", uintptr_t(p));
|
|
MT_recording = false;
|
|
auto count = MT_alloc_count;
|
|
allocatedPtrArray.Add(uintptr_t(p)); // this can allocate memory, so don't record that.
|
|
allocatedPtrInfoArray.Add(count); // this can allocate memory, so don't record that.
|
|
MT_recording = true;
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
|
|
#if defined(IS_UEFI_MODULE)
|
|
|
|
VOID *
|
|
PhaseAllocatePool (
|
|
IN EFI_MEMORY_TYPE MemoryType,
|
|
IN UINTN AllocationSize
|
|
)
|
|
#else
|
|
|
|
void* my_malloc(size_t AllocationSize)
|
|
|
|
#endif
|
|
{
|
|
VOID *Memory = NULL;
|
|
|
|
#ifdef JIEF_DEBUG
|
|
if ( MT_alloc_count == 4028 || MT_alloc_count == MT_count_to_break_into ) {
|
|
NOP;
|
|
}
|
|
#endif
|
|
if ( MT_recording )
|
|
{
|
|
Memory = _real_malloc(MemoryType, AllocationSize+24);
|
|
if ( !Memory ) return NULL;
|
|
|
|
*(uint64_t*)Memory = AllocationSize;
|
|
|
|
// void* p = ((uint64_t*)Memory + 1) ;
|
|
|
|
*((uint64_t*)Memory + 1) = MAGIC_BEGINNING;
|
|
*(uint64_t*)( ((uint8_t*)Memory) + 16 + AllocationSize ) = MAGIC_END;
|
|
if ( MT_recording ) {
|
|
MT_import( ((uint8_t*)Memory) + 16 );
|
|
++MT_alloc_count; // do this only if !MT_recording because MT_import is doing an allocation.
|
|
}
|
|
return ((uint8_t*)Memory) + 16;
|
|
|
|
}else{
|
|
Memory = _real_malloc(MemoryType, AllocationSize);
|
|
return Memory;
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(IS_UEFI_MODULE)
|
|
|
|
//void (EFIAPI FreePool)(IN void *MemoryPlus16)
|
|
VOID
|
|
EFIAPI
|
|
PhaseFreePool (IN VOID *MemoryPlus16)
|
|
|
|
#else
|
|
|
|
void my_free(IN void *MemoryPlus16)
|
|
|
|
#endif
|
|
{
|
|
if ( !MemoryPlus16 ) return;
|
|
|
|
uintptr_t ref2 = uintptr_t(MemoryPlus16);
|
|
auto idx = allocatedPtrArray.indexOf(ref2);
|
|
if ( idx == MAX_XSIZE ) {
|
|
if ( MT_report_deleting_non_recoded_ptr ) {
|
|
DBG("ERROR : Delete non recorded ptr %llx\n", uintptr_t(MemoryPlus16));
|
|
}
|
|
real_free(MemoryPlus16);
|
|
return;
|
|
}
|
|
|
|
uint8_t* Memory = ((uint8_t*)MemoryPlus16) - 16;
|
|
uint64_t AllocationSize = *(uint64_t*)Memory;
|
|
|
|
if ( *((uint64_t*)Memory + 1) != MAGIC_BEGINNING ) {
|
|
DBG("ERROR : Buffer underrun for ptr %llx count %lld\n", uintptr_t(MemoryPlus16), allocatedPtrInfoArray[idx]);
|
|
}
|
|
if ( *(uint64_t*)( ((uint8_t*)Memory) + 16 + AllocationSize ) != MAGIC_END ) {
|
|
DBG("ERROR : Buffer overrun for ptr %llx count %lld\n", uintptr_t(MemoryPlus16), allocatedPtrInfoArray[idx]);
|
|
}
|
|
allocatedPtrArray.RemoveAtIndex(idx);
|
|
allocatedPtrInfoArray.RemoveAtIndex(idx);
|
|
real_free( Memory );
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
|
|
void MemoryTrackerCheck()
|
|
{
|
|
size_t nb_ptr = allocatedPtrArray.length();
|
|
DBG("-- %zu pointers :\n", nb_ptr);
|
|
for( size_t idx=0 ; idx < nb_ptr ; ++idx )
|
|
{
|
|
uint8_t* Memory = ((uint8_t*)allocatedPtrArray[idx]) - 16;
|
|
uint64_t AllocationSize = *(uint64_t*)Memory;
|
|
|
|
if ( *((uint64_t*)Memory + 1) != MAGIC_BEGINNING ) {
|
|
DBG("Buffer underrun for ptr %llx count %lld\n", uintptr_t(Memory + 16), allocatedPtrInfoArray[idx]);
|
|
}
|
|
if ( *(uint64_t*)( ((uint8_t*)Memory) + 16 + AllocationSize ) != MAGIC_END ) {
|
|
DBG("Buffer overrun for ptr %llx count %lld\n", uintptr_t(Memory + 16), allocatedPtrInfoArray[idx]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MemoryTrackerInit()
|
|
{
|
|
MT_alloc_count = 0;
|
|
MT_recording = false;
|
|
MT_report_deleting_non_recoded_ptr = false;
|
|
}
|
|
|
|
|
|
/*
|
|
* In fact, the hook is already in place. We just have to activate it now.
|
|
*/
|
|
void MemoryTrackerInstallHook()
|
|
{
|
|
MT_recording = true;
|
|
MT_report_deleting_non_recoded_ptr = true;
|
|
}
|
|
|
|
void MT_outputDanglingPtr()
|
|
{
|
|
size_t nb_ptr = allocatedPtrArray.length();
|
|
DBG("-- %zu lost pointer :\n", nb_ptr);
|
|
for( size_t idx=0 ; idx < nb_ptr ; ++idx ) {
|
|
DBG(" Dangling ptr %llx count=%lld\n", allocatedPtrArray[idx], allocatedPtrInfoArray[idx]);
|
|
}
|
|
}
|
|
uint64_t MT_getAllocCount() { return MT_alloc_count; };
|
|
uint64_t MT_getDanglingPtrCount() { return allocatedPtrArray.length(); };
|
|
|
|
|
|
|
|
MemoryStopRecord::MemoryStopRecord() : recording(MT_recording) { MT_recording = false; };
|
|
MemoryStopRecord::~MemoryStopRecord() { MT_recording = recording; };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
//
|
|
// MTArray
|
|
//
|
|
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
|
|
template<class TYPE>
|
|
MTArray<TYPE>::MTArray() : m_data(0), m_len(0), m_allocatedSize(4096)
|
|
{
|
|
m_data = (TYPE*)real_malloc(4096 * sizeof(TYPE));
|
|
if ( !m_data ) {
|
|
#ifdef JIEF_DEBUG
|
|
panic("MTArray<TYPE>:: MTArray() : OldAllocatePool(%zu) returned NULL. System halted\n", 4096 * sizeof(TYPE));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
template<class TYPE>
|
|
size_t MTArray<TYPE>::indexOf(TYPE e) const
|
|
{
|
|
size_t i;
|
|
|
|
for ( i=0 ; i<length() ; i+=1 ) {
|
|
if ( m_data[i] == e ) return i;
|
|
}
|
|
return MAX_XSIZE;
|
|
}
|
|
|
|
/* CheckSize() // nNewSize is number of TYPE, not in bytes */
|
|
template<class TYPE>
|
|
void MTArray<TYPE>::CheckSize(size_t nNewSize, size_t nGrowBy)
|
|
{
|
|
//MTArray_DBG("CheckSize: m_len=%d, m_size=%d, nGrowBy=%d, nNewSize=%d\n", m_len, m_size, nGrowBy, nNewSize);
|
|
if ( nNewSize > m_allocatedSize ) {
|
|
nNewSize += nGrowBy;
|
|
TYPE* new_data;
|
|
new_data = (TYPE*)real_malloc(nNewSize * sizeof(TYPE));
|
|
if ( !new_data ) {
|
|
#ifdef JIEF_DEBUG
|
|
panic("MTArray<TYPE>::CheckSize(nNewSize=%zu, nGrowBy=%zu) : OldAllocatePool(%zu, %lu, %" PRIuPTR ") returned NULL. System halted\n", nNewSize, nGrowBy, m_allocatedSize, nNewSize*sizeof(TYPE), (uintptr_t)m_data);
|
|
#endif
|
|
}
|
|
memcpy(new_data, m_data, m_allocatedSize * sizeof(TYPE));
|
|
real_free(m_data);
|
|
m_data = new_data;
|
|
// memset(&_Data[_Size], 0, (nNewSize-_Size) * sizeof(TYPE)); // Could help for debugging, but zeroing in not needed.
|
|
m_allocatedSize = nNewSize;
|
|
}
|
|
}
|
|
|
|
/* CheckSize() */
|
|
template<class TYPE>
|
|
void MTArray<TYPE>::CheckSize(size_t nNewSize)
|
|
{
|
|
CheckSize(nNewSize, 4096);
|
|
}
|
|
|
|
/* Add(TYPE, size_t) */
|
|
template<class TYPE>
|
|
size_t MTArray<TYPE>::Add(const TYPE newElement, size_t count)
|
|
{
|
|
// MTArray_DBG("size_t MTArray<TYPE>::Add(const TYPE newElement, size_t count) -> Enter. count=%d _Len=%d _Size=%d\n", count, m_len, m_size);
|
|
size_t i;
|
|
|
|
CheckSize(m_len+count);
|
|
for ( i=0 ; i<count ; i++ ) {
|
|
m_data[m_len+i] = newElement;
|
|
}
|
|
m_len += count;
|
|
return m_len-count;
|
|
}
|
|
|
|
|
|
/* RemoveAtIndex(size_t) */
|
|
template<class TYPE>
|
|
void MTArray<TYPE>::RemoveAtIndex(size_t nIndex)
|
|
{
|
|
if ( nIndex < m_len ) {
|
|
if ( nIndex<m_len-1 ) memmove(&m_data[nIndex], &m_data[nIndex+1], (m_len-nIndex-1)*sizeof(TYPE));
|
|
m_len -= 1;
|
|
return;
|
|
}
|
|
#if defined(_DEBUG) && defined(TRACE)
|
|
TRACE("MTArray::Remove(size_t) -> nIndex > m_len\n");
|
|
#endif
|
|
}
|
|
|
|
|
|
/* FreeAndRemoveAtIndex(size_t) */
|
|
template<class TYPE>
|
|
void MTArray<TYPE>::FreeAndRemoveAtIndex(size_t nIndex)
|
|
{
|
|
if ( nIndex < m_len ) {
|
|
#ifdef UNIT_TESTS_MACOS // won't be needed soon as I'll improve the EFI mock
|
|
free(m_data[nIndex]);
|
|
#else
|
|
OldFreePool(m_data[nIndex]);
|
|
#endif
|
|
if ( nIndex<m_len-1 ) memmove(&m_data[nIndex], &m_data[nIndex+1], (m_len-nIndex-1)*sizeof(TYPE));
|
|
m_len -= 1;
|
|
return;
|
|
}
|
|
#if defined(_DEBUG) && defined(TRACE)
|
|
TRACE("MTArray::FreeAndRemoveAtIndex(size_t) -> nIndex > m_len\n");
|
|
#endif
|
|
}
|
|
|
|
|
|
#undef malloc
|
|
#undef free
|
|
|
|
|
|
void* real_malloc(EFI_MEMORY_TYPE MemoryType, size_t size)
|
|
{
|
|
#if defined(IS_UEFI_MODULE)
|
|
void* Memory;
|
|
EFI_STATUS Status = gBS->AllocatePool(MemoryType, size, &Memory); // AllocatePool in MemoryAllocationLib uses EfiBootServicesData, not EfiConventionalMemory
|
|
if (EFI_ERROR(Status)) return NULL;
|
|
return Memory;
|
|
#else
|
|
return malloc(size);
|
|
#endif
|
|
}
|
|
void* real_malloc(size_t size) { return real_malloc(EfiBootServicesData, size); }
|
|
|
|
void real_free(void* p)
|
|
{
|
|
#if defined(IS_UEFI_MODULE)
|
|
EFI_STATUS Status = gBS->FreePool(p);
|
|
if (EFI_ERROR(Status)) {
|
|
// What to do ?
|
|
}
|
|
#else
|
|
free(p);
|
|
#endif
|
|
}
|
|
|
|
#if defined(IS_UEFI_MODULE)
|
|
void* my_malloc(size_t size) { return PhaseAllocatePool(EfiBootServicesData, size); }
|
|
void my_free(IN void *p) { FreePool(p); }
|
|
#endif
|
|
|
|
//#if !defined(IS_UEFI_MODULE)
|
|
//extern "C" {
|
|
//void* malloc(size_t size);
|
|
//void free(void* p);
|
|
//} //extern C
|
|
//#endif // !defined(IS_UEFI_MODULE)
|
|
|
|
|
|
#else // MEMORY_TRACKER_ENABLED
|
|
|
|
void MemoryTrackerInit() {};
|
|
void MemoryTrackerInstallHook() {};
|
|
void MT_outputDanglingPtr() {};
|
|
uint64_t MT_getAllocCount() { return 0; };
|
|
uint64_t MT_getDanglingPtrCount() { return 0; };
|
|
MemoryStopRecord::MemoryStopRecord() {};
|
|
MemoryStopRecord::~MemoryStopRecord() {};
|
|
void MemoryTrackerCheck() {};
|
|
|
|
|
|
#undef malloc
|
|
#undef free
|
|
|
|
extern "C" {
|
|
|
|
// we don't use MemoryTracker. Let's define passthrough function to avoid having to have to remove function hooks.
|
|
|
|
void* my_malloc(size_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
void my_free(void* p)
|
|
{
|
|
free(p);
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
|
|
#endif// MEMORY_TRACKER_ENABLED
|