aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/gcc/ada/g-debpoo.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8/gcc/ada/g-debpoo.adb')
-rw-r--r--gcc-4.8/gcc/ada/g-debpoo.adb1725
1 files changed, 0 insertions, 1725 deletions
diff --git a/gcc-4.8/gcc/ada/g-debpoo.adb b/gcc-4.8/gcc/ada/g-debpoo.adb
deleted file mode 100644
index 5ee63d989..000000000
--- a/gcc-4.8/gcc/ada/g-debpoo.adb
+++ /dev/null
@@ -1,1725 +0,0 @@
-------------------------------------------------------------------------------
--- --
--- GNAT COMPILER COMPONENTS --
--- --
--- G N A T . D E B U G _ P O O L S --
--- --
--- B o d y --
--- --
--- Copyright (C) 1992-2012, Free Software Foundation, Inc. --
--- --
--- GNAT is free software; you can redistribute it and/or modify it under --
--- terms of the GNU General Public License as published by the Free Soft- --
--- ware Foundation; either version 3, or (at your option) any later ver- --
--- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
--- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
--- or FITNESS FOR A PARTICULAR PURPOSE. --
--- --
--- As a special exception under Section 7 of GPL version 3, you are granted --
--- additional permissions described in the GCC Runtime Library Exception, --
--- version 3.1, as published by the Free Software Foundation. --
--- --
--- You should have received a copy of the GNU General Public License and --
--- a copy of the GCC Runtime Library Exception along with this program; --
--- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
--- <http://www.gnu.org/licenses/>. --
--- --
--- GNAT was originally developed by the GNAT team at New York University. --
--- Extensive contributions were provided by Ada Core Technologies Inc. --
--- --
-------------------------------------------------------------------------------
-
-with Ada.Exceptions.Traceback;
-with GNAT.IO; use GNAT.IO;
-
-with System.Address_Image;
-with System.Memory; use System.Memory;
-with System.Soft_Links; use System.Soft_Links;
-
-with System.Traceback_Entries; use System.Traceback_Entries;
-
-with GNAT.HTable;
-with GNAT.Traceback; use GNAT.Traceback;
-
-with Ada.Unchecked_Conversion;
-
-package body GNAT.Debug_Pools is
-
- Default_Alignment : constant := Standard'Maximum_Alignment;
- -- Alignment used for the memory chunks returned by Allocate. Using this
- -- value guarantees that this alignment will be compatible with all types
- -- and at the same time makes it easy to find the location of the extra
- -- header allocated for each chunk.
-
- Max_Ignored_Levels : constant Natural := 10;
- -- Maximum number of levels that will be ignored in backtraces. This is so
- -- that we still have enough significant levels in the tracebacks returned
- -- to the user.
- --
- -- The value 10 is chosen as being greater than the maximum callgraph
- -- in this package. Its actual value is not really relevant, as long as it
- -- is high enough to make sure we still have enough frames to return to
- -- the user after we have hidden the frames internal to this package.
-
- ---------------------------
- -- Back Trace Hash Table --
- ---------------------------
-
- -- This package needs to store one set of tracebacks for each allocation
- -- point (when was it allocated or deallocated). This would use too much
- -- memory, so the tracebacks are actually stored in a hash table, and
- -- we reference elements in this hash table instead.
-
- -- This hash-table will remain empty if the discriminant Stack_Trace_Depth
- -- for the pools is set to 0.
-
- -- This table is a global table, that can be shared among all debug pools
- -- with no problems.
-
- type Header is range 1 .. 1023;
- -- Number of elements in the hash-table
-
- type Tracebacks_Array_Access
- is access GNAT.Traceback.Tracebacks_Array;
-
- type Traceback_Kind is (Alloc, Dealloc, Indirect_Alloc, Indirect_Dealloc);
-
- type Traceback_Htable_Elem;
- type Traceback_Htable_Elem_Ptr
- is access Traceback_Htable_Elem;
-
- type Traceback_Htable_Elem is record
- Traceback : Tracebacks_Array_Access;
- Kind : Traceback_Kind;
- Count : Natural;
- Total : Byte_Count;
- Next : Traceback_Htable_Elem_Ptr;
- end record;
-
- -- Subprograms used for the Backtrace_Htable instantiation
-
- procedure Set_Next
- (E : Traceback_Htable_Elem_Ptr;
- Next : Traceback_Htable_Elem_Ptr);
- pragma Inline (Set_Next);
-
- function Next
- (E : Traceback_Htable_Elem_Ptr) return Traceback_Htable_Elem_Ptr;
- pragma Inline (Next);
-
- function Get_Key
- (E : Traceback_Htable_Elem_Ptr) return Tracebacks_Array_Access;
- pragma Inline (Get_Key);
-
- function Hash (T : Tracebacks_Array_Access) return Header;
- pragma Inline (Hash);
-
- function Equal (K1, K2 : Tracebacks_Array_Access) return Boolean;
- -- Why is this not inlined???
-
- -- The hash table for back traces
-
- package Backtrace_Htable is new GNAT.HTable.Static_HTable
- (Header_Num => Header,
- Element => Traceback_Htable_Elem,
- Elmt_Ptr => Traceback_Htable_Elem_Ptr,
- Null_Ptr => null,
- Set_Next => Set_Next,
- Next => Next,
- Key => Tracebacks_Array_Access,
- Get_Key => Get_Key,
- Hash => Hash,
- Equal => Equal);
-
- -----------------------
- -- Allocations table --
- -----------------------
-
- type Allocation_Header;
- type Allocation_Header_Access is access Allocation_Header;
-
- type Traceback_Ptr_Or_Address is new System.Address;
- -- A type that acts as a C union, and is either a System.Address or a
- -- Traceback_Htable_Elem_Ptr.
-
- -- The following record stores extra information that needs to be
- -- memorized for each block allocated with the special debug pool.
-
- type Allocation_Header is record
- Allocation_Address : System.Address;
- -- Address of the block returned by malloc, possibly unaligned
-
- Block_Size : Storage_Offset;
- -- Needed only for advanced freeing algorithms (traverse all allocated
- -- blocks for potential references). This value is negated when the
- -- chunk of memory has been logically freed by the application. This
- -- chunk has not been physically released yet.
-
- Alloc_Traceback : Traceback_Htable_Elem_Ptr;
- -- ??? comment required
-
- Dealloc_Traceback : Traceback_Ptr_Or_Address;
- -- Pointer to the traceback for the allocation (if the memory chunk is
- -- still valid), or to the first deallocation otherwise. Make sure this
- -- is a thin pointer to save space.
- --
- -- Dealloc_Traceback is also for blocks that are still allocated to
- -- point to the previous block in the list. This saves space in this
- -- header, and make manipulation of the lists of allocated pointers
- -- faster.
-
- Next : System.Address;
- -- Point to the next block of the same type (either allocated or
- -- logically freed) in memory. This points to the beginning of the user
- -- data, and does not include the header of that block.
- end record;
-
- function Header_Of (Address : System.Address)
- return Allocation_Header_Access;
- pragma Inline (Header_Of);
- -- Return the header corresponding to a previously allocated address
-
- function To_Address is new Ada.Unchecked_Conversion
- (Traceback_Ptr_Or_Address, System.Address);
-
- function To_Address is new Ada.Unchecked_Conversion
- (System.Address, Traceback_Ptr_Or_Address);
-
- function To_Traceback is new Ada.Unchecked_Conversion
- (Traceback_Ptr_Or_Address, Traceback_Htable_Elem_Ptr);
-
- function To_Traceback is new Ada.Unchecked_Conversion
- (Traceback_Htable_Elem_Ptr, Traceback_Ptr_Or_Address);
-
- Header_Offset : constant Storage_Count :=
- Default_Alignment *
- ((Allocation_Header'Size / System.Storage_Unit
- + Default_Alignment - 1) / Default_Alignment);
- -- Offset of user data after allocation header
-
- Minimum_Allocation : constant Storage_Count :=
- Default_Alignment - 1 + Header_Offset;
- -- Minimal allocation: size of allocation_header rounded up to next
- -- multiple of default alignment + worst-case padding.
-
- -----------------------
- -- Local subprograms --
- -----------------------
-
- function Find_Or_Create_Traceback
- (Pool : Debug_Pool;
- Kind : Traceback_Kind;
- Size : Storage_Count;
- Ignored_Frame_Start : System.Address;
- Ignored_Frame_End : System.Address) return Traceback_Htable_Elem_Ptr;
- -- Return an element matching the current traceback (omitting the frames
- -- that are in the current package). If this traceback already existed in
- -- the htable, a pointer to this is returned to spare memory. Null is
- -- returned if the pool is set not to store tracebacks. If the traceback
- -- already existed in the table, the count is incremented so that
- -- Dump_Tracebacks returns useful results. All addresses up to, and
- -- including, an address between Ignored_Frame_Start .. Ignored_Frame_End
- -- are ignored.
-
- function Output_File (Pool : Debug_Pool) return File_Type;
- pragma Inline (Output_File);
- -- Returns file_type on which error messages have to be generated for Pool
-
- procedure Put_Line
- (File : File_Type;
- Depth : Natural;
- Traceback : Tracebacks_Array_Access;
- Ignored_Frame_Start : System.Address := System.Null_Address;
- Ignored_Frame_End : System.Address := System.Null_Address);
- -- Print Traceback to File. If Traceback is null, print the call_chain
- -- at the current location, up to Depth levels, ignoring all addresses
- -- up to the first one in the range:
- -- Ignored_Frame_Start .. Ignored_Frame_End
-
- package Validity is
- function Is_Valid (Storage : System.Address) return Boolean;
- pragma Inline (Is_Valid);
- -- Return True if Storage is the address of a block that the debug pool
- -- has under its control, in which case Header_Of may be used to access
- -- the associated allocation header.
-
- procedure Set_Valid (Storage : System.Address; Value : Boolean);
- pragma Inline (Set_Valid);
- -- Mark the address Storage as being under control of the memory pool
- -- (if Value is True), or not (if Value is False).
- end Validity;
-
- use Validity;
-
- procedure Set_Dead_Beef
- (Storage_Address : System.Address;
- Size_In_Storage_Elements : Storage_Count);
- -- Set the contents of the memory block pointed to by Storage_Address to
- -- the 16#DEADBEEF# pattern. If Size_In_Storage_Elements is not a multiple
- -- of the length of this pattern, the last instance may be partial.
-
- procedure Free_Physically (Pool : in out Debug_Pool);
- -- Start to physically release some memory to the system, until the amount
- -- of logically (but not physically) freed memory is lower than the
- -- expected amount in Pool.
-
- procedure Allocate_End;
- procedure Deallocate_End;
- procedure Dereference_End;
- -- These procedures are used as markers when computing the stacktraces,
- -- so that addresses in the debug pool itself are not reported to the user.
-
- Code_Address_For_Allocate_End : System.Address;
- Code_Address_For_Deallocate_End : System.Address;
- Code_Address_For_Dereference_End : System.Address;
- -- Taking the address of the above procedures will not work on some
- -- architectures (HPUX and VMS for instance). Thus we do the same thing
- -- that is done in a-except.adb, and get the address of labels instead
-
- procedure Skip_Levels
- (Depth : Natural;
- Trace : Tracebacks_Array;
- Start : out Natural;
- Len : in out Natural;
- Ignored_Frame_Start : System.Address;
- Ignored_Frame_End : System.Address);
- -- Set Start .. Len to the range of values from Trace that should be output
- -- to the user. This range of values excludes any address prior to the
- -- first one in Ignored_Frame_Start .. Ignored_Frame_End (basically
- -- addresses internal to this package). Depth is the number of levels that
- -- the user is interested in.
-
- ---------------
- -- Header_Of --
- ---------------
-
- function Header_Of (Address : System.Address)
- return Allocation_Header_Access
- is
- function Convert is new Ada.Unchecked_Conversion
- (System.Address, Allocation_Header_Access);
- begin
- return Convert (Address - Header_Offset);
- end Header_Of;
-
- --------------
- -- Set_Next --
- --------------
-
- procedure Set_Next
- (E : Traceback_Htable_Elem_Ptr;
- Next : Traceback_Htable_Elem_Ptr)
- is
- begin
- E.Next := Next;
- end Set_Next;
-
- ----------
- -- Next --
- ----------
-
- function Next
- (E : Traceback_Htable_Elem_Ptr) return Traceback_Htable_Elem_Ptr is
- begin
- return E.Next;
- end Next;
-
- -----------
- -- Equal --
- -----------
-
- function Equal (K1, K2 : Tracebacks_Array_Access) return Boolean is
- use Ada.Exceptions.Traceback;
- begin
- return K1.all = K2.all;
- end Equal;
-
- -------------
- -- Get_Key --
- -------------
-
- function Get_Key
- (E : Traceback_Htable_Elem_Ptr) return Tracebacks_Array_Access
- is
- begin
- return E.Traceback;
- end Get_Key;
-
- ----------
- -- Hash --
- ----------
-
- function Hash (T : Tracebacks_Array_Access) return Header is
- Result : Integer_Address := 0;
-
- begin
- for X in T'Range loop
- Result := Result + To_Integer (PC_For (T (X)));
- end loop;
-
- return Header (1 + Result mod Integer_Address (Header'Last));
- end Hash;
-
- -----------------
- -- Output_File --
- -----------------
-
- function Output_File (Pool : Debug_Pool) return File_Type is
- begin
- if Pool.Errors_To_Stdout then
- return Standard_Output;
- else
- return Standard_Error;
- end if;
- end Output_File;
-
- --------------
- -- Put_Line --
- --------------
-
- procedure Put_Line
- (File : File_Type;
- Depth : Natural;
- Traceback : Tracebacks_Array_Access;
- Ignored_Frame_Start : System.Address := System.Null_Address;
- Ignored_Frame_End : System.Address := System.Null_Address)
- is
- procedure Print (Tr : Tracebacks_Array);
- -- Print the traceback to standard_output
-
- -----------
- -- Print --
- -----------
-
- procedure Print (Tr : Tracebacks_Array) is
- begin
- for J in Tr'Range loop
- Put (File, "0x" & Address_Image (PC_For (Tr (J))) & ' ');
- end loop;
- Put (File, ASCII.LF);
- end Print;
-
- -- Start of processing for Put_Line
-
- begin
- if Traceback = null then
- declare
- Tr : aliased Tracebacks_Array (1 .. Depth + Max_Ignored_Levels);
- Start, Len : Natural;
-
- begin
- Call_Chain (Tr, Len);
- Skip_Levels (Depth, Tr, Start, Len,
- Ignored_Frame_Start, Ignored_Frame_End);
- Print (Tr (Start .. Len));
- end;
-
- else
- Print (Traceback.all);
- end if;
- end Put_Line;
-
- -----------------
- -- Skip_Levels --
- -----------------
-
- procedure Skip_Levels
- (Depth : Natural;
- Trace : Tracebacks_Array;
- Start : out Natural;
- Len : in out Natural;
- Ignored_Frame_Start : System.Address;
- Ignored_Frame_End : System.Address)
- is
- begin
- Start := Trace'First;
-
- while Start <= Len
- and then (PC_For (Trace (Start)) < Ignored_Frame_Start
- or else PC_For (Trace (Start)) > Ignored_Frame_End)
- loop
- Start := Start + 1;
- end loop;
-
- Start := Start + 1;
-
- -- Just in case: make sure we have a traceback even if Ignore_Till
- -- wasn't found.
-
- if Start > Len then
- Start := 1;
- end if;
-
- if Len - Start + 1 > Depth then
- Len := Depth + Start - 1;
- end if;
- end Skip_Levels;
-
- ------------------------------
- -- Find_Or_Create_Traceback --
- ------------------------------
-
- function Find_Or_Create_Traceback
- (Pool : Debug_Pool;
- Kind : Traceback_Kind;
- Size : Storage_Count;
- Ignored_Frame_Start : System.Address;
- Ignored_Frame_End : System.Address) return Traceback_Htable_Elem_Ptr
- is
- begin
- if Pool.Stack_Trace_Depth = 0 then
- return null;
- end if;
-
- declare
- Trace : aliased Tracebacks_Array
- (1 .. Integer (Pool.Stack_Trace_Depth) + Max_Ignored_Levels);
- Len, Start : Natural;
- Elem : Traceback_Htable_Elem_Ptr;
-
- begin
- Call_Chain (Trace, Len);
- Skip_Levels (Pool.Stack_Trace_Depth, Trace, Start, Len,
- Ignored_Frame_Start, Ignored_Frame_End);
-
- -- Check if the traceback is already in the table
-
- Elem :=
- Backtrace_Htable.Get (Trace (Start .. Len)'Unrestricted_Access);
-
- -- If not, insert it
-
- if Elem = null then
- Elem := new Traceback_Htable_Elem'
- (Traceback => new Tracebacks_Array'(Trace (Start .. Len)),
- Count => 1,
- Kind => Kind,
- Total => Byte_Count (Size),
- Next => null);
- Backtrace_Htable.Set (Elem);
-
- else
- Elem.Count := Elem.Count + 1;
- Elem.Total := Elem.Total + Byte_Count (Size);
- end if;
-
- return Elem;
- end;
- end Find_Or_Create_Traceback;
-
- --------------
- -- Validity --
- --------------
-
- package body Validity is
-
- -- The validity bits of the allocated blocks are kept in a has table.
- -- Each component of the hash table contains the validity bits for a
- -- 16 Mbyte memory chunk.
-
- -- The reason the validity bits are kept for chunks of memory rather
- -- than in a big array is that on some 64 bit platforms, it may happen
- -- that two chunk of allocated data are very far from each other.
-
- Memory_Chunk_Size : constant Integer_Address := 2 ** 24; -- 16 MB
- Validity_Divisor : constant := Default_Alignment * System.Storage_Unit;
-
- Max_Validity_Byte_Index : constant :=
- Memory_Chunk_Size / Validity_Divisor;
-
- subtype Validity_Byte_Index is Integer_Address
- range 0 .. Max_Validity_Byte_Index - 1;
-
- type Byte is mod 2 ** System.Storage_Unit;
-
- type Validity_Bits is array (Validity_Byte_Index) of Byte;
-
- type Validity_Bits_Ref is access all Validity_Bits;
- No_Validity_Bits : constant Validity_Bits_Ref := null;
-
- Max_Header_Num : constant := 1023;
-
- type Header_Num is range 0 .. Max_Header_Num - 1;
-
- function Hash (F : Integer_Address) return Header_Num;
-
- package Validy_Htable is new GNAT.HTable.Simple_HTable
- (Header_Num => Header_Num,
- Element => Validity_Bits_Ref,
- No_Element => No_Validity_Bits,
- Key => Integer_Address,
- Hash => Hash,
- Equal => "=");
- -- Table to keep the validity bit blocks for the allocated data
-
- function To_Pointer is new Ada.Unchecked_Conversion
- (System.Address, Validity_Bits_Ref);
-
- procedure Memset (A : Address; C : Integer; N : size_t);
- pragma Import (C, Memset, "memset");
-
- ----------
- -- Hash --
- ----------
-
- function Hash (F : Integer_Address) return Header_Num is
- begin
- return Header_Num (F mod Max_Header_Num);
- end Hash;
-
- --------------
- -- Is_Valid --
- --------------
-
- function Is_Valid (Storage : System.Address) return Boolean is
- Int_Storage : constant Integer_Address := To_Integer (Storage);
-
- begin
- -- The pool only returns addresses aligned on Default_Alignment so
- -- anything off cannot be a valid block address and we can return
- -- early in this case. We actually have to since our data structures
- -- map validity bits for such aligned addresses only.
-
- if Int_Storage mod Default_Alignment /= 0 then
- return False;
- end if;
-
- declare
- Block_Number : constant Integer_Address :=
- Int_Storage / Memory_Chunk_Size;
- Ptr : constant Validity_Bits_Ref :=
- Validy_Htable.Get (Block_Number);
- Offset : constant Integer_Address :=
- (Int_Storage -
- (Block_Number * Memory_Chunk_Size)) /
- Default_Alignment;
- Bit : constant Byte :=
- 2 ** Natural (Offset mod System.Storage_Unit);
- begin
- if Ptr = No_Validity_Bits then
- return False;
- else
- return (Ptr (Offset / System.Storage_Unit) and Bit) /= 0;
- end if;
- end;
- end Is_Valid;
-
- ---------------
- -- Set_Valid --
- ---------------
-
- procedure Set_Valid (Storage : System.Address; Value : Boolean) is
- Int_Storage : constant Integer_Address := To_Integer (Storage);
- Block_Number : constant Integer_Address :=
- Int_Storage / Memory_Chunk_Size;
- Ptr : Validity_Bits_Ref := Validy_Htable.Get (Block_Number);
- Offset : constant Integer_Address :=
- (Int_Storage - (Block_Number * Memory_Chunk_Size)) /
- Default_Alignment;
- Bit : constant Byte :=
- 2 ** Natural (Offset mod System.Storage_Unit);
-
- begin
- if Ptr = No_Validity_Bits then
-
- -- First time in this memory area: allocate a new block and put
- -- it in the table.
-
- if Value then
- Ptr := To_Pointer (Alloc (size_t (Max_Validity_Byte_Index)));
- Validy_Htable.Set (Block_Number, Ptr);
- Memset (Ptr.all'Address, 0, size_t (Max_Validity_Byte_Index));
- Ptr (Offset / System.Storage_Unit) := Bit;
- end if;
-
- else
- if Value then
- Ptr (Offset / System.Storage_Unit) :=
- Ptr (Offset / System.Storage_Unit) or Bit;
-
- else
- Ptr (Offset / System.Storage_Unit) :=
- Ptr (Offset / System.Storage_Unit) and (not Bit);
- end if;
- end if;
- end Set_Valid;
-
- end Validity;
-
- --------------
- -- Allocate --
- --------------
-
- procedure Allocate
- (Pool : in out Debug_Pool;
- Storage_Address : out Address;
- Size_In_Storage_Elements : Storage_Count;
- Alignment : Storage_Count)
- is
- pragma Unreferenced (Alignment);
- -- Ignored, we always force 'Default_Alignment
-
- type Local_Storage_Array is new Storage_Array
- (1 .. Size_In_Storage_Elements + Minimum_Allocation);
-
- type Ptr is access Local_Storage_Array;
- -- On some systems, we might want to physically protect pages against
- -- writing when they have been freed (of course, this is expensive in
- -- terms of wasted memory). To do that, all we should have to do it to
- -- set the size of this array to the page size. See mprotect().
-
- Current : Byte_Count;
- P : Ptr;
- Trace : Traceback_Htable_Elem_Ptr;
-
- begin
- <<Allocate_Label>>
- Lock_Task.all;
-
- -- If necessary, start physically releasing memory. The reason this is
- -- done here, although Pool.Logically_Deallocated has not changed above,
- -- is so that we do this only after a series of deallocations (e.g loop
- -- that deallocates a big array). If we were doing that in Deallocate,
- -- we might be physically freeing memory several times during the loop,
- -- which is expensive.
-
- if Pool.Logically_Deallocated >
- Byte_Count (Pool.Maximum_Logically_Freed_Memory)
- then
- Free_Physically (Pool);
- end if;
-
- -- Use standard (i.e. through malloc) allocations. This automatically
- -- raises Storage_Error if needed. We also try once more to physically
- -- release memory, so that even marked blocks, in the advanced scanning,
- -- are freed. Note that we do not initialize the storage array since it
- -- is not necessary to do so (however this will cause bogus valgrind
- -- warnings, which should simply be ignored).
-
- begin
- P := new Local_Storage_Array;
-
- exception
- when Storage_Error =>
- Free_Physically (Pool);
- P := new Local_Storage_Array;
- end;
-
- Storage_Address :=
- To_Address
- (Default_Alignment *
- ((To_Integer (P.all'Address) + Default_Alignment - 1)
- / Default_Alignment)
- + Integer_Address (Header_Offset));
- -- Computation is done in Integer_Address, not Storage_Offset, because
- -- the range of Storage_Offset may not be large enough.
-
- pragma Assert ((Storage_Address - System.Null_Address)
- mod Default_Alignment = 0);
- pragma Assert (Storage_Address + Size_In_Storage_Elements
- <= P.all'Address + P'Length);
-
- Trace := Find_Or_Create_Traceback
- (Pool, Alloc, Size_In_Storage_Elements,
- Allocate_Label'Address, Code_Address_For_Allocate_End);
-
- pragma Warnings (Off);
- -- Turn warning on alignment for convert call off. We know that in fact
- -- this conversion is safe since P itself is always aligned on
- -- Default_Alignment.
-
- Header_Of (Storage_Address).all :=
- (Allocation_Address => P.all'Address,
- Alloc_Traceback => Trace,
- Dealloc_Traceback => To_Traceback (null),
- Next => Pool.First_Used_Block,
- Block_Size => Size_In_Storage_Elements);
-
- pragma Warnings (On);
-
- -- Link this block in the list of used blocks. This will be used to list
- -- memory leaks in Print_Info, and for the advanced schemes of
- -- Physical_Free, where we want to traverse all allocated blocks and
- -- search for possible references.
-
- -- We insert in front, since most likely we'll be freeing the most
- -- recently allocated blocks first (the older one might stay allocated
- -- for the whole life of the application).
-
- if Pool.First_Used_Block /= System.Null_Address then
- Header_Of (Pool.First_Used_Block).Dealloc_Traceback :=
- To_Address (Storage_Address);
- end if;
-
- Pool.First_Used_Block := Storage_Address;
-
- -- Mark the new address as valid
-
- Set_Valid (Storage_Address, True);
-
- if Pool.Low_Level_Traces then
- Put (Output_File (Pool),
- "info: Allocated"
- & Storage_Count'Image (Size_In_Storage_Elements)
- & " bytes at 0x" & Address_Image (Storage_Address)
- & " (physically:"
- & Storage_Count'Image (Local_Storage_Array'Length)
- & " bytes at 0x" & Address_Image (P.all'Address)
- & "), at ");
- Put_Line (Output_File (Pool), Pool.Stack_Trace_Depth, null,
- Allocate_Label'Address,
- Code_Address_For_Deallocate_End);
- end if;
-
- -- Update internal data
-
- Pool.Allocated :=
- Pool.Allocated + Byte_Count (Size_In_Storage_Elements);
-
- Current := Pool.Allocated -
- Pool.Logically_Deallocated -
- Pool.Physically_Deallocated;
-
- if Current > Pool.High_Water then
- Pool.High_Water := Current;
- end if;
-
- Unlock_Task.all;
-
- exception
- when others =>
- Unlock_Task.all;
- raise;
- end Allocate;
-
- ------------------
- -- Allocate_End --
- ------------------
-
- -- DO NOT MOVE, this must be right after Allocate. This is similar to what
- -- is done in a-except, so that we can hide the traceback frames internal
- -- to this package
-
- procedure Allocate_End is
- begin
- <<Allocate_End_Label>>
- Code_Address_For_Allocate_End := Allocate_End_Label'Address;
- end Allocate_End;
-
- -------------------
- -- Set_Dead_Beef --
- -------------------
-
- procedure Set_Dead_Beef
- (Storage_Address : System.Address;
- Size_In_Storage_Elements : Storage_Count)
- is
- Dead_Bytes : constant := 4;
-
- type Data is mod 2 ** (Dead_Bytes * 8);
- for Data'Size use Dead_Bytes * 8;
-
- Dead : constant Data := 16#DEAD_BEEF#;
-
- type Dead_Memory is array
- (1 .. Size_In_Storage_Elements / Dead_Bytes) of Data;
- type Mem_Ptr is access Dead_Memory;
-
- type Byte is mod 2 ** 8;
- for Byte'Size use 8;
-
- type Dead_Memory_Bytes is array (0 .. 2) of Byte;
- type Dead_Memory_Bytes_Ptr is access Dead_Memory_Bytes;
-
- function From_Ptr is new Ada.Unchecked_Conversion
- (System.Address, Mem_Ptr);
-
- function From_Ptr is new Ada.Unchecked_Conversion
- (System.Address, Dead_Memory_Bytes_Ptr);
-
- M : constant Mem_Ptr := From_Ptr (Storage_Address);
- M2 : Dead_Memory_Bytes_Ptr;
- Modulo : constant Storage_Count :=
- Size_In_Storage_Elements mod Dead_Bytes;
- begin
- M.all := (others => Dead);
-
- -- Any bytes left (up to three of them)
-
- if Modulo /= 0 then
- M2 := From_Ptr (Storage_Address + M'Length * Dead_Bytes);
-
- M2 (0) := 16#DE#;
- if Modulo >= 2 then
- M2 (1) := 16#AD#;
-
- if Modulo >= 3 then
- M2 (2) := 16#BE#;
- end if;
- end if;
- end if;
- end Set_Dead_Beef;
-
- ---------------------
- -- Free_Physically --
- ---------------------
-
- procedure Free_Physically (Pool : in out Debug_Pool) is
- type Byte is mod 256;
- type Byte_Access is access Byte;
-
- function To_Byte is new Ada.Unchecked_Conversion
- (System.Address, Byte_Access);
-
- type Address_Access is access System.Address;
-
- function To_Address_Access is new Ada.Unchecked_Conversion
- (System.Address, Address_Access);
-
- In_Use_Mark : constant Byte := 16#D#;
- Free_Mark : constant Byte := 16#F#;
-
- Total_Freed : Storage_Count := 0;
-
- procedure Reset_Marks;
- -- Unmark all the logically freed blocks, so that they are considered
- -- for physical deallocation
-
- procedure Mark
- (H : Allocation_Header_Access; A : System.Address; In_Use : Boolean);
- -- Mark the user data block starting at A. For a block of size zero,
- -- nothing is done. For a block with a different size, the first byte
- -- is set to either "D" (in use) or "F" (free).
-
- function Marked (A : System.Address) return Boolean;
- -- Return true if the user data block starting at A might be in use
- -- somewhere else
-
- procedure Mark_Blocks;
- -- Traverse all allocated blocks, and search for possible references
- -- to logically freed blocks. Mark them appropriately
-
- procedure Free_Blocks (Ignore_Marks : Boolean);
- -- Physically release blocks. Only the blocks that haven't been marked
- -- will be released, unless Ignore_Marks is true.
-
- -----------------
- -- Free_Blocks --
- -----------------
-
- procedure Free_Blocks (Ignore_Marks : Boolean) is
- Header : Allocation_Header_Access;
- Tmp : System.Address := Pool.First_Free_Block;
- Next : System.Address;
- Previous : System.Address := System.Null_Address;
-
- begin
- while Tmp /= System.Null_Address
- and then Total_Freed < Pool.Minimum_To_Free
- loop
- Header := Header_Of (Tmp);
-
- -- If we know, or at least assume, the block is no longer
- -- referenced anywhere, we can free it physically.
-
- if Ignore_Marks or else not Marked (Tmp) then
-
- declare
- pragma Suppress (All_Checks);
- -- Suppress the checks on this section. If they are overflow
- -- errors, it isn't critical, and we'd rather avoid a
- -- Constraint_Error in that case.
- begin
- -- Note that block_size < zero for freed blocks
-
- Pool.Physically_Deallocated :=
- Pool.Physically_Deallocated -
- Byte_Count (Header.Block_Size);
-
- Pool.Logically_Deallocated :=
- Pool.Logically_Deallocated +
- Byte_Count (Header.Block_Size);
-
- Total_Freed := Total_Freed - Header.Block_Size;
- end;
-
- Next := Header.Next;
-
- if Pool.Low_Level_Traces then
- Put_Line
- (Output_File (Pool),
- "info: Freeing physical memory "
- & Storage_Count'Image
- ((abs Header.Block_Size) + Minimum_Allocation)
- & " bytes at 0x"
- & Address_Image (Header.Allocation_Address));
- end if;
-
- System.Memory.Free (Header.Allocation_Address);
- Set_Valid (Tmp, False);
-
- -- Remove this block from the list
-
- if Previous = System.Null_Address then
- Pool.First_Free_Block := Next;
- else
- Header_Of (Previous).Next := Next;
- end if;
-
- Tmp := Next;
-
- else
- Previous := Tmp;
- Tmp := Header.Next;
- end if;
- end loop;
- end Free_Blocks;
-
- ----------
- -- Mark --
- ----------
-
- procedure Mark
- (H : Allocation_Header_Access;
- A : System.Address;
- In_Use : Boolean)
- is
- begin
- if H.Block_Size /= 0 then
- To_Byte (A).all := (if In_Use then In_Use_Mark else Free_Mark);
- end if;
- end Mark;
-
- -----------------
- -- Mark_Blocks --
- -----------------
-
- procedure Mark_Blocks is
- Tmp : System.Address := Pool.First_Used_Block;
- Previous : System.Address;
- Last : System.Address;
- Pointed : System.Address;
- Header : Allocation_Header_Access;
-
- begin
- -- For each allocated block, check its contents. Things that look
- -- like a possible address are used to mark the blocks so that we try
- -- and keep them, for better detection in case of invalid access.
- -- This mechanism is far from being fool-proof: it doesn't check the
- -- stacks of the threads, doesn't check possible memory allocated not
- -- under control of this debug pool. But it should allow us to catch
- -- more cases.
-
- while Tmp /= System.Null_Address loop
- Previous := Tmp;
- Last := Tmp + Header_Of (Tmp).Block_Size;
- while Previous < Last loop
- -- ??? Should we move byte-per-byte, or consider that addresses
- -- are always aligned on 4-bytes boundaries ? Let's use the
- -- fastest for now.
-
- Pointed := To_Address_Access (Previous).all;
- if Is_Valid (Pointed) then
- Header := Header_Of (Pointed);
-
- -- Do not even attempt to mark blocks in use. That would
- -- screw up the whole application, of course.
-
- if Header.Block_Size < 0 then
- Mark (Header, Pointed, In_Use => True);
- end if;
- end if;
-
- Previous := Previous + System.Address'Size;
- end loop;
-
- Tmp := Header_Of (Tmp).Next;
- end loop;
- end Mark_Blocks;
-
- ------------
- -- Marked --
- ------------
-
- function Marked (A : System.Address) return Boolean is
- begin
- return To_Byte (A).all = In_Use_Mark;
- end Marked;
-
- -----------------
- -- Reset_Marks --
- -----------------
-
- procedure Reset_Marks is
- Current : System.Address := Pool.First_Free_Block;
- Header : Allocation_Header_Access;
- begin
- while Current /= System.Null_Address loop
- Header := Header_Of (Current);
- Mark (Header, Current, False);
- Current := Header.Next;
- end loop;
- end Reset_Marks;
-
- -- Start of processing for Free_Physically
-
- begin
- Lock_Task.all;
-
- if Pool.Advanced_Scanning then
-
- -- Reset the mark for each freed block
-
- Reset_Marks;
-
- Mark_Blocks;
- end if;
-
- Free_Blocks (Ignore_Marks => not Pool.Advanced_Scanning);
-
- -- The contract is that we need to free at least Minimum_To_Free bytes,
- -- even if this means freeing marked blocks in the advanced scheme
-
- if Total_Freed < Pool.Minimum_To_Free
- and then Pool.Advanced_Scanning
- then
- Pool.Marked_Blocks_Deallocated := True;
- Free_Blocks (Ignore_Marks => True);
- end if;
-
- Unlock_Task.all;
-
- exception
- when others =>
- Unlock_Task.all;
- raise;
- end Free_Physically;
-
- ----------------
- -- Deallocate --
- ----------------
-
- procedure Deallocate
- (Pool : in out Debug_Pool;
- Storage_Address : Address;
- Size_In_Storage_Elements : Storage_Count;
- Alignment : Storage_Count)
- is
- pragma Unreferenced (Alignment);
-
- Header : constant Allocation_Header_Access :=
- Header_Of (Storage_Address);
- Valid : Boolean;
- Previous : System.Address;
-
- begin
- <<Deallocate_Label>>
- Lock_Task.all;
- Valid := Is_Valid (Storage_Address);
-
- if not Valid then
- Unlock_Task.all;
- if Pool.Raise_Exceptions then
- raise Freeing_Not_Allocated_Storage;
- else
- Put (Output_File (Pool),
- "error: Freeing not allocated storage, at ");
- Put_Line (Output_File (Pool), Pool.Stack_Trace_Depth, null,
- Deallocate_Label'Address,
- Code_Address_For_Deallocate_End);
- end if;
-
- elsif Header.Block_Size < 0 then
- Unlock_Task.all;
- if Pool.Raise_Exceptions then
- raise Freeing_Deallocated_Storage;
- else
- Put (Output_File (Pool),
- "error: Freeing already deallocated storage, at ");
- Put_Line (Output_File (Pool), Pool.Stack_Trace_Depth, null,
- Deallocate_Label'Address,
- Code_Address_For_Deallocate_End);
- Put (Output_File (Pool), " Memory already deallocated at ");
- Put_Line
- (Output_File (Pool), 0,
- To_Traceback (Header.Dealloc_Traceback).Traceback);
- Put (Output_File (Pool), " Memory was allocated at ");
- Put_Line (Output_File (Pool), 0, Header.Alloc_Traceback.Traceback);
- end if;
-
- else
- -- Some sort of codegen problem or heap corruption caused the
- -- Size_In_Storage_Elements to be wrongly computed.
- -- The code below is all based on the assumption that Header.all
- -- is not corrupted, such that the error is non-fatal.
-
- if Header.Block_Size /= Size_In_Storage_Elements then
- Put_Line (Output_File (Pool),
- "error: Deallocate size "
- & Storage_Count'Image (Size_In_Storage_Elements)
- & " does not match allocate size "
- & Storage_Count'Image (Header.Block_Size));
- end if;
-
- if Pool.Low_Level_Traces then
- Put (Output_File (Pool),
- "info: Deallocated"
- & Storage_Count'Image (Size_In_Storage_Elements)
- & " bytes at 0x" & Address_Image (Storage_Address)
- & " (physically"
- & Storage_Count'Image (Header.Block_Size + Minimum_Allocation)
- & " bytes at 0x" & Address_Image (Header.Allocation_Address)
- & "), at ");
- Put_Line (Output_File (Pool), Pool.Stack_Trace_Depth, null,
- Deallocate_Label'Address,
- Code_Address_For_Deallocate_End);
- Put (Output_File (Pool), " Memory was allocated at ");
- Put_Line (Output_File (Pool), 0, Header.Alloc_Traceback.Traceback);
- end if;
-
- -- Remove this block from the list of used blocks
-
- Previous :=
- To_Address (Header.Dealloc_Traceback);
-
- if Previous = System.Null_Address then
- Pool.First_Used_Block := Header_Of (Pool.First_Used_Block).Next;
-
- if Pool.First_Used_Block /= System.Null_Address then
- Header_Of (Pool.First_Used_Block).Dealloc_Traceback :=
- To_Traceback (null);
- end if;
-
- else
- Header_Of (Previous).Next := Header.Next;
-
- if Header.Next /= System.Null_Address then
- Header_Of
- (Header.Next).Dealloc_Traceback := To_Address (Previous);
- end if;
- end if;
-
- -- Update the header
-
- Header.all :=
- (Allocation_Address => Header.Allocation_Address,
- Alloc_Traceback => Header.Alloc_Traceback,
- Dealloc_Traceback => To_Traceback
- (Find_Or_Create_Traceback
- (Pool, Dealloc,
- Size_In_Storage_Elements,
- Deallocate_Label'Address,
- Code_Address_For_Deallocate_End)),
- Next => System.Null_Address,
- Block_Size => -Header.Block_Size);
-
- if Pool.Reset_Content_On_Free then
- Set_Dead_Beef (Storage_Address, -Header.Block_Size);
- end if;
-
- Pool.Logically_Deallocated :=
- Pool.Logically_Deallocated + Byte_Count (-Header.Block_Size);
-
- -- Link this free block with the others (at the end of the list, so
- -- that we can start releasing the older blocks first later on).
-
- if Pool.First_Free_Block = System.Null_Address then
- Pool.First_Free_Block := Storage_Address;
- Pool.Last_Free_Block := Storage_Address;
-
- else
- Header_Of (Pool.Last_Free_Block).Next := Storage_Address;
- Pool.Last_Free_Block := Storage_Address;
- end if;
-
- -- Do not physically release the memory here, but in Alloc.
- -- See comment there for details.
-
- Unlock_Task.all;
- end if;
-
- exception
- when others =>
- Unlock_Task.all;
- raise;
- end Deallocate;
-
- --------------------
- -- Deallocate_End --
- --------------------
-
- -- DO NOT MOVE, this must be right after Deallocate
-
- -- See Allocate_End
-
- -- This is making assumptions about code order that may be invalid ???
-
- procedure Deallocate_End is
- begin
- <<Deallocate_End_Label>>
- Code_Address_For_Deallocate_End := Deallocate_End_Label'Address;
- end Deallocate_End;
-
- -----------------
- -- Dereference --
- -----------------
-
- procedure Dereference
- (Pool : in out Debug_Pool;
- Storage_Address : Address;
- Size_In_Storage_Elements : Storage_Count;
- Alignment : Storage_Count)
- is
- pragma Unreferenced (Alignment, Size_In_Storage_Elements);
-
- Valid : constant Boolean := Is_Valid (Storage_Address);
- Header : Allocation_Header_Access;
-
- begin
- -- Locking policy: we do not do any locking in this procedure. The
- -- tables are only read, not written to, and although a problem might
- -- appear if someone else is modifying the tables at the same time, this
- -- race condition is not intended to be detected by this storage_pool (a
- -- now invalid pointer would appear as valid). Instead, we prefer
- -- optimum performance for dereferences.
-
- <<Dereference_Label>>
-
- if not Valid then
- if Pool.Raise_Exceptions then
- raise Accessing_Not_Allocated_Storage;
- else
- Put (Output_File (Pool),
- "error: Accessing not allocated storage, at ");
- Put_Line (Output_File (Pool), Pool.Stack_Trace_Depth, null,
- Dereference_Label'Address,
- Code_Address_For_Dereference_End);
- end if;
-
- else
- Header := Header_Of (Storage_Address);
-
- if Header.Block_Size < 0 then
- if Pool.Raise_Exceptions then
- raise Accessing_Deallocated_Storage;
- else
- Put (Output_File (Pool),
- "error: Accessing deallocated storage, at ");
- Put_Line
- (Output_File (Pool), Pool.Stack_Trace_Depth, null,
- Dereference_Label'Address,
- Code_Address_For_Dereference_End);
- Put (Output_File (Pool), " First deallocation at ");
- Put_Line
- (Output_File (Pool),
- 0, To_Traceback (Header.Dealloc_Traceback).Traceback);
- Put (Output_File (Pool), " Initial allocation at ");
- Put_Line
- (Output_File (Pool),
- 0, Header.Alloc_Traceback.Traceback);
- end if;
- end if;
- end if;
- end Dereference;
-
- ---------------------
- -- Dereference_End --
- ---------------------
-
- -- DO NOT MOVE: this must be right after Dereference
-
- -- See Allocate_End
-
- -- This is making assumptions about code order that may be invalid ???
-
- procedure Dereference_End is
- begin
- <<Dereference_End_Label>>
- Code_Address_For_Dereference_End := Dereference_End_Label'Address;
- end Dereference_End;
-
- ----------------
- -- Print_Info --
- ----------------
-
- procedure Print_Info
- (Pool : Debug_Pool;
- Cumulate : Boolean := False;
- Display_Slots : Boolean := False;
- Display_Leaks : Boolean := False)
- is
-
- package Backtrace_Htable_Cumulate is new GNAT.HTable.Static_HTable
- (Header_Num => Header,
- Element => Traceback_Htable_Elem,
- Elmt_Ptr => Traceback_Htable_Elem_Ptr,
- Null_Ptr => null,
- Set_Next => Set_Next,
- Next => Next,
- Key => Tracebacks_Array_Access,
- Get_Key => Get_Key,
- Hash => Hash,
- Equal => Equal);
- -- This needs a comment ??? probably some of the ones below do too???
-
- Data : Traceback_Htable_Elem_Ptr;
- Elem : Traceback_Htable_Elem_Ptr;
- Current : System.Address;
- Header : Allocation_Header_Access;
- K : Traceback_Kind;
-
- begin
- Put_Line
- ("Total allocated bytes : " &
- Byte_Count'Image (Pool.Allocated));
-
- Put_Line
- ("Total logically deallocated bytes : " &
- Byte_Count'Image (Pool.Logically_Deallocated));
-
- Put_Line
- ("Total physically deallocated bytes : " &
- Byte_Count'Image (Pool.Physically_Deallocated));
-
- if Pool.Marked_Blocks_Deallocated then
- Put_Line ("Marked blocks were physically deallocated. This is");
- Put_Line ("potentially dangerous, and you might want to run");
- Put_Line ("again with a lower value of Minimum_To_Free");
- end if;
-
- Put_Line
- ("Current Water Mark: " &
- Byte_Count'Image
- (Pool.Allocated - Pool.Logically_Deallocated
- - Pool.Physically_Deallocated));
-
- Put_Line
- ("High Water Mark: " &
- Byte_Count'Image (Pool.High_Water));
-
- Put_Line ("");
-
- if Display_Slots then
- Data := Backtrace_Htable.Get_First;
- while Data /= null loop
- if Data.Kind in Alloc .. Dealloc then
- Elem :=
- new Traceback_Htable_Elem'
- (Traceback => new Tracebacks_Array'(Data.Traceback.all),
- Count => Data.Count,
- Kind => Data.Kind,
- Total => Data.Total,
- Next => null);
- Backtrace_Htable_Cumulate.Set (Elem);
-
- if Cumulate then
- K := (if Data.Kind = Alloc then Indirect_Alloc
- else Indirect_Dealloc);
-
- -- Propagate the direct call to all its parents
-
- for T in Data.Traceback'First + 1 .. Data.Traceback'Last loop
- Elem := Backtrace_Htable_Cumulate.Get
- (Data.Traceback
- (T .. Data.Traceback'Last)'Unrestricted_Access);
-
- -- If not, insert it
-
- if Elem = null then
- Elem := new Traceback_Htable_Elem'
- (Traceback => new Tracebacks_Array'
- (Data.Traceback (T .. Data.Traceback'Last)),
- Count => Data.Count,
- Kind => K,
- Total => Data.Total,
- Next => null);
- Backtrace_Htable_Cumulate.Set (Elem);
-
- -- Properly take into account that the subprograms
- -- indirectly called might be doing either allocations
- -- or deallocations. This needs to be reflected in the
- -- counts.
-
- else
- Elem.Count := Elem.Count + Data.Count;
-
- if K = Elem.Kind then
- Elem.Total := Elem.Total + Data.Total;
-
- elsif Elem.Total > Data.Total then
- Elem.Total := Elem.Total - Data.Total;
-
- else
- Elem.Kind := K;
- Elem.Total := Data.Total - Elem.Total;
- end if;
- end if;
- end loop;
- end if;
-
- Data := Backtrace_Htable.Get_Next;
- end if;
- end loop;
-
- Put_Line ("List of allocations/deallocations: ");
-
- Data := Backtrace_Htable_Cumulate.Get_First;
- while Data /= null loop
- case Data.Kind is
- when Alloc => Put ("alloc (count:");
- when Indirect_Alloc => Put ("indirect alloc (count:");
- when Dealloc => Put ("free (count:");
- when Indirect_Dealloc => Put ("indirect free (count:");
- end case;
-
- Put (Natural'Image (Data.Count) & ", total:" &
- Byte_Count'Image (Data.Total) & ") ");
-
- for T in Data.Traceback'Range loop
- Put ("0x" & Address_Image (PC_For (Data.Traceback (T))) & ' ');
- end loop;
-
- Put_Line ("");
-
- Data := Backtrace_Htable_Cumulate.Get_Next;
- end loop;
-
- Backtrace_Htable_Cumulate.Reset;
- end if;
-
- if Display_Leaks then
- Put_Line ("");
- Put_Line ("List of not deallocated blocks:");
-
- -- Do not try to group the blocks with the same stack traces
- -- together. This is done by the gnatmem output.
-
- Current := Pool.First_Used_Block;
- while Current /= System.Null_Address loop
- Header := Header_Of (Current);
-
- Put ("Size: " & Storage_Count'Image (Header.Block_Size) & " at: ");
-
- for T in Header.Alloc_Traceback.Traceback'Range loop
- Put ("0x" & Address_Image
- (PC_For (Header.Alloc_Traceback.Traceback (T))) & ' ');
- end loop;
-
- Put_Line ("");
- Current := Header.Next;
- end loop;
- end if;
- end Print_Info;
-
- ------------------
- -- Storage_Size --
- ------------------
-
- function Storage_Size (Pool : Debug_Pool) return Storage_Count is
- pragma Unreferenced (Pool);
- begin
- return Storage_Count'Last;
- end Storage_Size;
-
- ---------------
- -- Configure --
- ---------------
-
- procedure Configure
- (Pool : in out Debug_Pool;
- Stack_Trace_Depth : Natural := Default_Stack_Trace_Depth;
- Maximum_Logically_Freed_Memory : SSC := Default_Max_Freed;
- Minimum_To_Free : SSC := Default_Min_Freed;
- Reset_Content_On_Free : Boolean := Default_Reset_Content;
- Raise_Exceptions : Boolean := Default_Raise_Exceptions;
- Advanced_Scanning : Boolean := Default_Advanced_Scanning;
- Errors_To_Stdout : Boolean := Default_Errors_To_Stdout;
- Low_Level_Traces : Boolean := Default_Low_Level_Traces)
- is
- begin
- Pool.Stack_Trace_Depth := Stack_Trace_Depth;
- Pool.Maximum_Logically_Freed_Memory := Maximum_Logically_Freed_Memory;
- Pool.Reset_Content_On_Free := Reset_Content_On_Free;
- Pool.Raise_Exceptions := Raise_Exceptions;
- Pool.Minimum_To_Free := Minimum_To_Free;
- Pool.Advanced_Scanning := Advanced_Scanning;
- Pool.Errors_To_Stdout := Errors_To_Stdout;
- Pool.Low_Level_Traces := Low_Level_Traces;
- end Configure;
-
- ----------------
- -- Print_Pool --
- ----------------
-
- procedure Print_Pool (A : System.Address) is
- Storage : constant Address := A;
- Valid : constant Boolean := Is_Valid (Storage);
- Header : Allocation_Header_Access;
-
- begin
- -- We might get Null_Address if the call from gdb was done
- -- incorrectly. For instance, doing a "print_pool(my_var)" passes 0x0,
- -- instead of passing the value of my_var
-
- if A = System.Null_Address then
- Put_Line
- (Standard_Output, "Memory not under control of the storage pool");
- return;
- end if;
-
- if not Valid then
- Put_Line
- (Standard_Output, "Memory not under control of the storage pool");
-
- else
- Header := Header_Of (Storage);
- Put_Line (Standard_Output, "0x" & Address_Image (A)
- & " allocated at:");
- Put_Line (Standard_Output, 0, Header.Alloc_Traceback.Traceback);
-
- if To_Traceback (Header.Dealloc_Traceback) /= null then
- Put_Line (Standard_Output, "0x" & Address_Image (A)
- & " logically freed memory, deallocated at:");
- Put_Line
- (Standard_Output, 0,
- To_Traceback (Header.Dealloc_Traceback).Traceback);
- end if;
- end if;
- end Print_Pool;
-
- -----------------------
- -- Print_Info_Stdout --
- -----------------------
-
- procedure Print_Info_Stdout
- (Pool : Debug_Pool;
- Cumulate : Boolean := False;
- Display_Slots : Boolean := False;
- Display_Leaks : Boolean := False)
- is
- procedure Stdout_Put (S : String);
- procedure Stdout_Put_Line (S : String);
- -- Wrappers for Put and Put_Line that ensure we always write to stdout
- -- instead of the current output file defined in GNAT.IO.
-
- procedure Internal is new Print_Info
- (Put_Line => Stdout_Put_Line,
- Put => Stdout_Put);
-
- ----------------
- -- Stdout_Put --
- ----------------
-
- procedure Stdout_Put (S : String) is
- begin
- Put_Line (Standard_Output, S);
- end Stdout_Put;
-
- ---------------------
- -- Stdout_Put_Line --
- ---------------------
-
- procedure Stdout_Put_Line (S : String) is
- begin
- Put_Line (Standard_Output, S);
- end Stdout_Put_Line;
-
- -- Start of processing for Print_Info_Stdout
-
- begin
- Internal (Pool, Cumulate, Display_Slots, Display_Leaks);
- end Print_Info_Stdout;
-
- ------------------
- -- Dump_Gnatmem --
- ------------------
-
- procedure Dump_Gnatmem (Pool : Debug_Pool; File_Name : String) is
- type File_Ptr is new System.Address;
-
- function fopen (Path : String; Mode : String) return File_Ptr;
- pragma Import (C, fopen);
-
- procedure fwrite
- (Ptr : System.Address;
- Size : size_t;
- Nmemb : size_t;
- Stream : File_Ptr);
-
- procedure fwrite
- (Str : String;
- Size : size_t;
- Nmemb : size_t;
- Stream : File_Ptr);
- pragma Import (C, fwrite);
-
- procedure fputc (C : Integer; Stream : File_Ptr);
- pragma Import (C, fputc);
-
- procedure fclose (Stream : File_Ptr);
- pragma Import (C, fclose);
-
- Address_Size : constant size_t :=
- System.Address'Max_Size_In_Storage_Elements;
- -- Size in bytes of a pointer
-
- File : File_Ptr;
- Current : System.Address;
- Header : Allocation_Header_Access;
- Actual_Size : size_t;
- Num_Calls : Integer;
- Tracebk : Tracebacks_Array_Access;
- Dummy_Time : Duration := 1.0;
-
- begin
- File := fopen (File_Name & ASCII.NUL, "wb" & ASCII.NUL);
- fwrite ("GMEM DUMP" & ASCII.LF, 10, 1, File);
- fwrite (Dummy_Time'Address, Duration'Max_Size_In_Storage_Elements, 1,
- File);
-
- -- List of not deallocated blocks (see Print_Info)
-
- Current := Pool.First_Used_Block;
- while Current /= System.Null_Address loop
- Header := Header_Of (Current);
-
- Actual_Size := size_t (Header.Block_Size);
- Tracebk := Header.Alloc_Traceback.Traceback;
- Num_Calls := Tracebk'Length;
-
- -- (Code taken from memtrack.adb in GNAT's sources)
-
- -- Logs allocation call using the format:
-
- -- 'A' <mem addr> <size chunk> <len backtrace> <addr1> ... <addrn>
-
- fputc (Character'Pos ('A'), File);
- fwrite (Current'Address, Address_Size, 1, File);
- fwrite (Actual_Size'Address, size_t'Max_Size_In_Storage_Elements, 1,
- File);
- fwrite (Dummy_Time'Address, Duration'Max_Size_In_Storage_Elements, 1,
- File);
- fwrite (Num_Calls'Address, Integer'Max_Size_In_Storage_Elements, 1,
- File);
-
- for J in Tracebk'First .. Tracebk'First + Num_Calls - 1 loop
- declare
- Ptr : System.Address := PC_For (Tracebk (J));
- begin
- fwrite (Ptr'Address, Address_Size, 1, File);
- end;
- end loop;
-
- Current := Header.Next;
- end loop;
-
- fclose (File);
- end Dump_Gnatmem;
-
--- Package initialization
-
-begin
- Allocate_End;
- Deallocate_End;
- Dereference_End;
-end GNAT.Debug_Pools;