Yes, the general idea is to override PureBasic library procedures with macros and and add whatever you are tracking to a list.
Here is my current implementation, at the moment I only have support for memory and files, but it is easy to add whatever needed (it is thread safe). I use a module for this because all my code is module based, however the drawback is that you need to remember to do
before use.
Code: Select all
DeclareModule Tracker
EnableExplicit
CompilerIf #PB_Compiler_Debugger
Macro AllocateStructureProxy(name, command = AllocateStructure)
command(name)
EndMacro
Macro AllocateMemory(size, flags = #Null)
Tracker::__TrackAllocateMemory(size, flags, #PB_Compiler_File, #PB_Compiler_Line)
EndMacro
Macro ReAllocateMemory(mem, size, flags = #Null)
Tracker::__TrackReAllocateMemory(mem, size, flags, #PB_Compiler_File, #PB_Compiler_Line)
EndMacro
Macro FreeMemory(mem)
Tracker::__TrackFreeMemory(mem)
EndMacro
Macro AllocateStructure(name)
Tracker::__TrackAllocateStructure(AllocateStructureProxy(name), SizeOf(name), #PB_Compiler_File, #PB_Compiler_Line)
EndMacro
Macro FreeStructure(mem)
Tracker::__TrackFreeStructure(mem)
EndMacro
Macro CreateFile(file, filename, flags = #Null)
Tracker::__TrackCreateFile(file, filename, flags, #PB_Compiler_File, #PB_Compiler_Line)
EndMacro
Macro OpenFile(file, filename, flags = #Null)
Tracker::__TrackOpenFile(file, filename, flags, #PB_Compiler_File, #PB_Compiler_Line)
EndMacro
Macro ReadFile(file, filename, flags = #Null)
Tracker::__TrackReadFile(file, filename, flags, #PB_Compiler_File, #PB_Compiler_Line)
EndMacro
Macro CloseFile(file)
Tracker::__TrackCloseFile(file)
EndMacro
Declare __TrackAllocateMemory(size.q, flags, trackFile.s, trackLine.i)
Declare __TrackReAllocateMemory(*mem, size.q, flags, trackFile.s, trackLine.i)
Declare __TrackFreeMemory(*mem)
Declare __TrackAllocateStructure(*mem, size.q, trackFile.s, trackLine.i)
Declare __TrackFreeStructure(*mem)
Declare __TrackCreateFile(file, filename.s, flags, trackFile.s, trackLine.i)
Declare __TrackOpenFile(file, filename.s, flags, trackFile.s, trackLine.i)
Declare __TrackReadFile(file, filename.s, flags, trackFile.s, trackLine.i)
Declare __TrackCloseFile(file)
CompilerEndIf
Declare PrintAllocations()
EndDeclareModule
Module Tracker
CompilerIf #PB_Compiler_Debugger
CompilerIf #PB_Compiler_Thread
Global mutex = CreateMutex()
Macro Lock()
LockMutex(mutex)
EndMacro
Macro Unlock()
UnlockMutex(mutex)
EndMacro
CompilerElse
Macro Lock()
EndMacro
Macro Unlock()
EndMacro
CompilerEndIf
Macro AllocateMemoryProxy(size, flags, command = AllocateMemory)
command(size, flags)
EndMacro
Macro ReAllocateMemoryProxy(mem, size, flags, command = ReAllocateMemory)
command(mem, size, flags)
EndMacro
Macro FreeMemoryProxy(mem, command = FreeMemory)
command(mem)
EndMacro
Macro FreeStructureProxy(mem, command = FreeStructure)
command(mem)
EndMacro
Structure MemoryAllocation
*mem
size.q
trackFile.s
trackLine.i
EndStructure
Global NewList memoryAllocations.MemoryAllocation()
Procedure TrackMemoryAllocation(*mem, size, trackFile.s, trackLine.i)
Lock()
If *mem And AddElement(memoryAllocations())
memoryAllocations()\mem = *mem
memoryAllocations()\size = size
memoryAllocations()\trackFile = trackFile
memoryAllocations()\trackLine = trackLine
EndIf
Unlock()
EndProcedure
Procedure __TrackAllocateMemory(size.q, flags, trackFile.s, trackLine.i)
Protected *mem = AllocateMemoryProxy(size, flags)
TrackMemoryAllocation(*mem, size, trackFile, trackLine)
ProcedureReturn *mem
EndProcedure
Procedure __TrackReAllocateMemory(*mem, size.q, flags, trackFile.s, trackLine.i)
Protected *new = ReAllocateMemoryProxy(*mem, size, flags)
If *new
Lock()
ForEach memoryAllocations()
If memoryAllocations()\mem = *mem
DeleteElement(memoryAllocations())
Break
EndIf
Next
Unlock()
TrackMemoryAllocation(*new, size, trackFile, trackLine)
EndIf
ProcedureReturn *new
EndProcedure
Procedure __TrackFreeMemory(*mem)
Lock()
ForEach memoryAllocations()
If memoryAllocations()\mem = *mem
DeleteElement(memoryAllocations())
Break
EndIf
Next
Unlock()
FreeMemoryProxy(*mem)
EndProcedure
Procedure __TrackAllocateStructure(*mem, size.q, trackFile.s, trackLine.i)
TrackMemoryAllocation(*mem, size, trackFile, trackLine)
ProcedureReturn *mem
EndProcedure
Procedure __TrackFreeStructure(*mem)
Lock()
ForEach memoryAllocations()
If memoryAllocations()\mem = *mem
DeleteElement(memoryAllocations())
Break
EndIf
Next
Unlock()
FreeStructureProxy(*mem)
EndProcedure
Macro CreateFileProxy(file, filename, flags, command = CreateFile)
command(file, filename, flags)
EndMacro
Macro OpenFileProxy(file, filename, flags, command = OpenFile)
command(file, filename, flags)
EndMacro
Macro ReadFileProxy(file, filename, flags, command = ReadFile)
command(file, filename, flags)
EndMacro
Macro CloseFileProxy(file, command = CloseFile)
command(file)
EndMacro
Structure FileAllocation
file.i
filename.s
trackFile.s
trackLine.i
EndStructure
Global NewList fileAllocations.FileAllocation()
Procedure TrackFileOperation(id, file, filename.s, trackFile.s, trackLine.i)
Lock()
If id And AddElement(fileAllocations())
If file = #PB_Any
fileAllocations()\file = id
Else
fileAllocations()\file = file
EndIf
fileAllocations()\filename = filename
fileAllocations()\trackFile = trackFile
fileAllocations()\trackLine = trackLine
EndIf
Unlock()
EndProcedure
Procedure __TrackCreateFile(file, filename.s, flags, trackFile.s, trackLine.i)
Protected id = CreateFileProxy(file, filename, flags)
TrackFileOperation(id, file, filename, trackFile, trackLine)
ProcedureReturn id
EndProcedure
Procedure __TrackOpenFile(file, filename.s, flags, trackFile.s, trackLine.i)
Protected id = OpenFileProxy(file, filename, flags)
TrackFileOperation(id, file, filename, trackFile, trackLine)
ProcedureReturn id
EndProcedure
Procedure __TrackReadFile(file, filename.s, flags, trackFile.s, trackLine.i)
Protected id = ReadFileProxy(file, filename, flags)
TrackFileOperation(id, file, filename, trackFile, trackLine)
ProcedureReturn id
EndProcedure
Procedure __TrackCloseFile(file)
Lock()
If LastElement(fileAllocations())
Repeat
If fileAllocations()\file = file
DeleteElement(fileAllocations())
Break
EndIf
Until PreviousElement(fileAllocations()) = #False
LastElement(fileAllocations())
EndIf
Unlock()
CloseFileProxy(file)
EndProcedure
CompilerEndIf
Procedure PrintAllocations()
CompilerIf #PB_Compiler_Debugger
Lock()
If ListSize(memoryAllocations())
Debug "-[ Allocated Memory ]------"
ForEach memoryAllocations()
Debug memoryAllocations()\trackFile +
":" + memoryAllocations()\trackLine +
" Size: " + memoryAllocations()\size +
" Address: " + memoryAllocations()\mem
Next
Debug "---------------------------"
EndIf
If ListSize(fileAllocations())
Debug "-[ Allocated Files ]------"
ForEach fileAllocations()
Debug fileAllocations()\trackFile +
":" + fileAllocations()\trackLine +
" File: " + fileAllocations()\filename +
" Id: " + fileAllocations()\file
Next
Debug "---------------------------"
EndIf
Unlock()
CompilerEndIf
EndProcedure
EndModule