blob: 17ff5cfbbd3ed4fb7488486f13640d5b02dfdbbb [file] [log] [blame]
/** @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 */