/** @file | |
File for memory allocation tracking functions. | |
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "MyAlloc.h" | |
#if USE_MYALLOC | |
// | |
// Get back to original alloc/free calls. | |
// | |
#undef malloc | |
#undef calloc | |
#undef realloc | |
#undef free | |
// | |
// Start of allocation list. | |
// | |
STATIC MY_ALLOC_STRUCT *MyAllocData = NULL; | |
// | |
// | |
// | |
STATIC UINT32 MyAllocHeadMagik = MYALLOC_HEAD_MAGIK; | |
STATIC UINT32 MyAllocTailMagik = MYALLOC_TAIL_MAGIK; | |
/** | |
Check for corruptions in the allocated memory chain. If a corruption | |
is detection program operation stops w/ an exit(1) call. | |
@param Final When FALSE, MyCheck() returns if the allocated memory chain | |
has not been corrupted. When TRUE, MyCheck() returns if there | |
are no un-freed allocations. If there are un-freed allocations, | |
they are displayed and exit(1) is called. | |
@param File Set to __FILE__ by macro expansion. | |
@param Line Set to __LINE__ by macro expansion. | |
**/ | |
VOID | |
MyCheck ( | |
BOOLEAN Final, | |
UINT8 File[], | |
UINTN Line | |
) | |
{ | |
MY_ALLOC_STRUCT *Tmp; | |
// | |
// Check parameters. | |
// | |
if (File == NULL) { | |
printf ( | |
"\nMyCheck(Final=%u, File=NULL, Line=%u)" | |
"Invalid parameter(s).\n", | |
Final, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
if (Line == 0) { | |
printf ( | |
"\nMyCheck(Final=%u, File=%s, Line=%u)" | |
"Invalid parameter(s).\n", | |
Final, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
if (strlen ((CHAR8 *)File) == 0) { | |
printf ( | |
"\nMyCheck(Final=%u, File=%s, Line=%u)" | |
"Invalid parameter.\n", | |
Final, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
// | |
// Check structure contents. | |
// | |
for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) { | |
if (memcmp(Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik) || | |
memcmp(&Tmp->Buffer[Tmp->Size + sizeof(UINT32)], &MyAllocTailMagik, sizeof MyAllocTailMagik)) { | |
break; | |
} | |
} | |
// | |
// If Tmp is not NULL, the structure is corrupt. | |
// | |
if (Tmp != NULL) { | |
printf ( | |
"\nMyCheck(Final=%u, File=%s, Line=%u)""\nStructure corrupted!" | |
"\nFile=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n", | |
Final, | |
File, | |
(unsigned)Line, | |
Tmp->File, | |
(unsigned) Tmp->Line, | |
(unsigned) Tmp->Size, | |
(unsigned) *(UINT32 *) (Tmp->Buffer), | |
(unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)]) | |
); | |
exit (1); | |
} | |
// | |
// If Final is TRUE, display the state of the structure chain. | |
// | |
if (Final) { | |
if (MyAllocData != NULL) { | |
printf ( | |
"\nMyCheck(Final=%u, File=%s, Line=%u)" | |
"\nSome allocated items have not been freed.\n", | |
Final, | |
File, | |
(unsigned)Line | |
); | |
for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) { | |
printf ( | |
"File=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n", | |
Tmp->File, | |
(unsigned) Tmp->Line, | |
(unsigned) Tmp->Size, | |
(unsigned) *(UINT32 *) (Tmp->Buffer), | |
(unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)]) | |
); | |
} | |
} | |
} | |
} | |
/** | |
Allocate a new link in the allocation chain along with enough storage | |
for the File[] string, requested Size and alignment overhead. If | |
memory cannot be allocated or the allocation chain has been corrupted, | |
exit(1) will be called. | |
@param Size Number of bytes (UINT8) requested by the called. | |
Size cannot be zero. | |
@param File Set to __FILE__ by macro expansion. | |
@param Line Set to __LINE__ by macro expansion. | |
@return Pointer to the caller's buffer. | |
**/ | |
VOID * | |
MyAlloc ( | |
UINTN Size, | |
UINT8 File[], | |
UINTN Line | |
) | |
{ | |
MY_ALLOC_STRUCT *Tmp; | |
UINTN Len; | |
// | |
// Check for invalid parameters. | |
// | |
if (File == NULL) { | |
printf ( | |
"\nMyAlloc(Size=%u, File=NULL, Line=%u)" | |
"\nInvalid parameter(s).\n", | |
(unsigned)Size, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
if (Size == 0 || Line == 0) { | |
printf ( | |
"\nMyAlloc(Size=%u, File=%s, Line=%u)" | |
"\nInvalid parameter(s).\n", | |
(unsigned)Size, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
Len = strlen ((CHAR8 *)File); | |
if (Len == 0) { | |
printf ( | |
"\nMyAlloc(Size=%u, File=%s, Line=%u)" | |
"\nInvalid parameter.\n", | |
(unsigned)Size, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
// | |
// Check the allocation list for corruption. | |
// | |
MyCheck (0, (UINT8 *)__FILE__, __LINE__); | |
// | |
// Allocate a new entry. | |
// | |
Tmp = calloc ( | |
1, | |
sizeof (MY_ALLOC_STRUCT) + Len + 1 + sizeof (UINT64) + Size + (sizeof MyAllocHeadMagik) + (sizeof MyAllocTailMagik) | |
); | |
if (Tmp == NULL) { | |
printf ( | |
"\nMyAlloc(Size=%u, File=%s, Line=%u)" | |
"\nOut of memory.\n", | |
(unsigned)Size, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
// | |
// Fill in the new entry. | |
// | |
Tmp->File = ((UINT8 *) Tmp) + sizeof (MY_ALLOC_STRUCT); | |
strcpy ((CHAR8 *)Tmp->File, (CHAR8 *)File); | |
Tmp->Line = Line; | |
Tmp->Size = Size; | |
Tmp->Buffer = (UINT8 *) (((UINTN) Tmp + Len + 9) &~7); | |
memcpy (Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik); | |
memcpy ( | |
&Tmp->Buffer[Size + sizeof (UINT32)], | |
&MyAllocTailMagik, | |
sizeof MyAllocTailMagik | |
); | |
Tmp->Next = MyAllocData; | |
Tmp->Cksum = (UINTN) Tmp + (UINTN) (Tmp->Next) + Tmp->Line + Tmp->Size + (UINTN) (Tmp->File) + (UINTN) (Tmp->Buffer); | |
MyAllocData = Tmp; | |
return Tmp->Buffer + sizeof (UINT32); | |
} | |
/** | |
This does a MyAlloc(), memcpy() and MyFree(). There is no optimization | |
for shrinking or expanding buffers. An invalid parameter will cause | |
MyRealloc() to fail with a call to exit(1). | |
@param Ptr Pointer to the caller's buffer to be re-allocated. | |
@param Size Size of new buffer. Size cannot be zero. | |
@param File Set to __FILE__ by macro expansion. | |
@param Line Set to __LINE__ by macro expansion. | |
@return Pointer to new caller's buffer. | |
**/ | |
VOID * | |
MyRealloc ( | |
VOID *Ptr, | |
UINTN Size, | |
UINT8 File[], | |
UINTN Line | |
) | |
{ | |
MY_ALLOC_STRUCT *Tmp; | |
VOID *Buffer; | |
// | |
// Check for invalid parameter(s). | |
// | |
if (File == NULL) { | |
printf ( | |
"\nMyRealloc(Ptr=%p, Size=%u, File=NULL, Line=%u)" | |
"\nInvalid parameter(s).\n", | |
Ptr, | |
(unsigned)Size, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
if (Size == 0 || Line == 0) { | |
printf ( | |
"\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" | |
"\nInvalid parameter(s).\n", | |
Ptr, | |
(unsigned)Size, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
if (strlen ((CHAR8 *)File) == 0) { | |
printf ( | |
"\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" | |
"\nInvalid parameter.\n", | |
Ptr, | |
(unsigned)Size, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
// | |
// Find existing buffer in allocation list. | |
// | |
if (Ptr == NULL) { | |
Tmp = NULL; | |
} else if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) { | |
Tmp = MyAllocData; | |
} else { | |
for (Tmp = MyAllocData;; Tmp = Tmp->Next) { | |
if (Tmp->Next == NULL) { | |
printf ( | |
"\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" | |
"\nCould not find buffer.\n", | |
Ptr, | |
(unsigned)Size, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
Tmp = Tmp->Next; | |
} | |
} | |
// | |
// Allocate new buffer, copy old data, free old buffer. | |
// | |
Buffer = MyAlloc (Size, File, Line); | |
if (Buffer != NULL && Tmp != NULL) { | |
memcpy ( | |
Buffer, | |
&Tmp->Buffer[sizeof (UINT32)], | |
((Size <= Tmp->Size) ? Size : Tmp->Size) | |
); | |
MyFree (Ptr, (UINT8 *)__FILE__, __LINE__); | |
} | |
return Buffer; | |
} | |
/** | |
Release a previously allocated buffer. Invalid parameters will cause | |
MyFree() to fail with an exit(1) call. | |
@param Ptr Pointer to the caller's buffer to be freed. | |
A NULL pointer will be ignored. | |
@param File Set to __FILE__ by macro expansion. | |
@param Line Set to __LINE__ by macro expansion. | |
**/ | |
VOID | |
MyFree ( | |
VOID *Ptr, | |
UINT8 File[], | |
UINTN Line | |
) | |
{ | |
MY_ALLOC_STRUCT *Tmp; | |
MY_ALLOC_STRUCT *Tmp2; | |
// | |
// Check for invalid parameter(s). | |
// | |
if (File == NULL) { | |
printf ( | |
"\nMyFree(Ptr=%p, File=NULL, Line=%u)" | |
"\nInvalid parameter(s).\n", | |
Ptr, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
if (Line == 0) { | |
printf ( | |
"\nMyFree(Ptr=%p, File=%s, Line=%u)" | |
"\nInvalid parameter(s).\n", | |
Ptr, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
if (strlen ((CHAR8 *)File) == 0) { | |
printf ( | |
"\nMyFree(Ptr=%p, File=%s, Line=%u)" | |
"\nInvalid parameter.\n", | |
Ptr, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
// | |
// Freeing NULL is always valid. | |
// | |
if (Ptr == NULL) { | |
return ; | |
} | |
// | |
// Fail if nothing is allocated. | |
// | |
if (MyAllocData == NULL) { | |
printf ( | |
"\nMyFree(Ptr=%p, File=%s, Line=%u)" | |
"\nCalled before memory allocated.\n", | |
Ptr, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
// | |
// Check for corrupted allocation list. | |
// | |
MyCheck (0, (UINT8 *)__FILE__, __LINE__); | |
// | |
// Need special check for first item in list. | |
// | |
if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) { | |
// | |
// Unlink first item in list. | |
// | |
Tmp = MyAllocData; | |
MyAllocData = MyAllocData->Next; | |
} else { | |
// | |
// Walk list looking for matching item. | |
// | |
for (Tmp = MyAllocData;; Tmp = Tmp->Next) { | |
// | |
// Fail if end of list is reached. | |
// | |
if (Tmp->Next == NULL) { | |
printf ( | |
"\nMyFree(Ptr=%p, File=%s, Line=%u)\n" | |
"\nNot found.\n", | |
Ptr, | |
File, | |
(unsigned)Line | |
); | |
exit (1); | |
} | |
// | |
// Leave loop when match is found. | |
// | |
if (&Tmp->Next->Buffer[sizeof (UINT32)] == Ptr) { | |
break; | |
} | |
} | |
// | |
// Unlink item from list. | |
// | |
Tmp2 = Tmp->Next; | |
Tmp->Next = Tmp->Next->Next; | |
Tmp = Tmp2; | |
} | |
// | |
// Release item. | |
// | |
free (Tmp); | |
} | |
#endif /* USE_MYALLOC */ | |
/* eof - MyAlloc.c */ |