aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.4.3/gcc/ada/gnatmem.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.4.3/gcc/ada/gnatmem.adb')
-rw-r--r--gcc-4.4.3/gcc/ada/gnatmem.adb815
1 files changed, 0 insertions, 815 deletions
diff --git a/gcc-4.4.3/gcc/ada/gnatmem.adb b/gcc-4.4.3/gcc/ada/gnatmem.adb
deleted file mode 100644
index d6ac07834..000000000
--- a/gcc-4.4.3/gcc/ada/gnatmem.adb
+++ /dev/null
@@ -1,815 +0,0 @@
-------------------------------------------------------------------------------
--- --
--- GNAT COMPILER COMPONENTS --
--- --
--- G N A T M E M --
--- --
--- B o d y --
--- --
--- Copyright (C) 1997-2008, AdaCore --
--- --
--- 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. See the GNU General Public License --
--- for more details. You should have received a copy of the GNU General --
--- Public License distributed with GNAT; see file COPYING3. If not, go to --
--- http://www.gnu.org/licenses for a complete copy of the license. --
--- --
--- GNAT was originally developed by the GNAT team at New York University. --
--- Extensive contributions were provided by Ada Core Technologies Inc. --
--- --
-------------------------------------------------------------------------------
-
--- GNATMEM is a utility that tracks memory leaks. It is based on a simple
--- idea:
-
--- - Read the allocation log generated by the application linked using
--- instrumented memory allocation and deallocation (see memtrack.adb for
--- this circuitry). To get access to this functionality, the application
--- must be relinked with library libgmem.a:
-
--- $ gnatmake my_prog -largs -lgmem
-
--- The running my_prog will produce a file named gmem.out that will be
--- parsed by gnatmem.
-
--- - Record a reference to the allocated memory on each allocation call
-
--- - Suppress this reference on deallocation
-
--- - At the end of the program, remaining references are potential leaks.
--- sort them out the best possible way in order to locate the root of
--- the leak.
-
--- This capability is not supported on all platforms, please refer to
--- memtrack.adb for further information.
-
--- In order to help finding out the real leaks, the notion of "allocation
--- root" is defined. An allocation root is a specific point in the program
--- execution generating memory allocation where data is collected (such as
--- number of allocations, amount of memory allocated, high water mark, etc.)
-
-with Ada.Float_Text_IO;
-with Ada.Integer_Text_IO;
-with Ada.Text_IO; use Ada.Text_IO;
-
-with System; use System;
-with System.Storage_Elements; use System.Storage_Elements;
-
-with GNAT.Command_Line; use GNAT.Command_Line;
-with GNAT.Heap_Sort_G;
-with GNAT.OS_Lib; use GNAT.OS_Lib;
-with GNAT.HTable; use GNAT.HTable;
-
-with Gnatvsn; use Gnatvsn;
-with Memroot; use Memroot;
-
-procedure Gnatmem is
-
- package Int_IO renames Ada.Integer_Text_IO;
-
- ------------------------
- -- Other Declarations --
- ------------------------
-
- type Storage_Elmt is record
- Elmt : Character;
- -- * = End of log file
- -- A = found a ALLOC mark in the log
- -- D = found a DEALL mark in the log
-
- Address : Integer_Address;
- Size : Storage_Count;
- Timestamp : Duration;
- end record;
- -- This type is used to read heap operations from the log file.
- -- Elmt contains the type of the operation, which can be either
- -- allocation, deallocation, or a special mark indicating the
- -- end of the log file. Address is used to store address on the
- -- heap where a chunk was allocated/deallocated, size is only
- -- for A event and contains size of the allocation, and Timestamp
- -- is the clock value at the moment of allocation
-
- Log_Name : String_Access;
- -- Holds the name of the heap operations log file
-
- Program_Name : String_Access;
- -- Holds the name of the user executable
-
- function Read_Next return Storage_Elmt;
- -- Reads next dynamic storage operation from the log file
-
- function Mem_Image (X : Storage_Count) return String;
- -- X is a size in storage_element. Returns a value
- -- in Megabytes, Kilobytes or Bytes as appropriate.
-
- procedure Process_Arguments;
- -- Read command line arguments
-
- procedure Usage;
- -- Prints out the option help
-
- function Gmem_Initialize (Dumpname : String) return Boolean;
- -- Opens the file represented by Dumpname and prepares it for
- -- work. Returns False if the file does not have the correct format, True
- -- otherwise.
-
- procedure Gmem_A2l_Initialize (Exename : String);
- -- Initialises the convert_addresses interface by supplying it with
- -- the name of the executable file Exename
-
- -----------------------------------
- -- HTable address --> Allocation --
- -----------------------------------
-
- type Allocation is record
- Root : Root_Id;
- Size : Storage_Count;
- end record;
-
- type Address_Range is range 0 .. 4097;
- function H (A : Integer_Address) return Address_Range;
- No_Alloc : constant Allocation := (No_Root_Id, 0);
-
- package Address_HTable is new GNAT.HTable.Simple_HTable (
- Header_Num => Address_Range,
- Element => Allocation,
- No_Element => No_Alloc,
- Key => Integer_Address,
- Hash => H,
- Equal => "=");
-
- BT_Depth : Integer := 1;
-
- -- Some global statistics
-
- Global_Alloc_Size : Storage_Count := 0;
- -- Total number of bytes allocated during the lifetime of a program
-
- Global_High_Water_Mark : Storage_Count := 0;
- -- Largest amount of storage ever in use during the lifetime
-
- Global_Nb_Alloc : Integer := 0;
- -- Total number of allocations
-
- Global_Nb_Dealloc : Integer := 0;
- -- Total number of deallocations
-
- Nb_Root : Integer := 0;
- -- Total number of allocation roots
-
- Nb_Wrong_Deall : Integer := 0;
- -- Total number of wrong deallocations (i.e. without matching alloc)
-
- Minimum_Nb_Leaks : Integer := 1;
- -- How many unfreed allocs should be in a root for it to count as leak
-
- T0 : Duration := 0.0;
- -- The moment at which memory allocation routines initialized (should
- -- be pretty close to the moment the program started since there are
- -- always some allocations at RTL elaboration
-
- Tmp_Alloc : Allocation;
- Dump_Log_Mode : Boolean := False;
- Quiet_Mode : Boolean := False;
-
- ------------------------------
- -- Allocation Roots Sorting --
- ------------------------------
-
- Sort_Order : String (1 .. 3) := "nwh";
- -- This is the default order in which sorting criteria will be applied
- -- n - Total number of unfreed allocations
- -- w - Final watermark
- -- h - High watermark
-
- --------------------------------
- -- GMEM functionality binding --
- --------------------------------
-
- ---------------------
- -- Gmem_Initialize --
- ---------------------
-
- function Gmem_Initialize (Dumpname : String) return Boolean is
- function Initialize (Dumpname : System.Address) return Duration;
- pragma Import (C, Initialize, "__gnat_gmem_initialize");
-
- S : aliased String := Dumpname & ASCII.NUL;
-
- begin
- T0 := Initialize (S'Address);
- return T0 > 0.0;
- end Gmem_Initialize;
-
- -------------------------
- -- Gmem_A2l_Initialize --
- -------------------------
-
- procedure Gmem_A2l_Initialize (Exename : String) is
- procedure A2l_Initialize (Exename : System.Address);
- pragma Import (C, A2l_Initialize, "__gnat_gmem_a2l_initialize");
-
- S : aliased String := Exename & ASCII.NUL;
-
- begin
- A2l_Initialize (S'Address);
- end Gmem_A2l_Initialize;
-
- ---------------
- -- Read_Next --
- ---------------
-
- function Read_Next return Storage_Elmt is
- procedure Read_Next (buf : System.Address);
- pragma Import (C, Read_Next, "__gnat_gmem_read_next");
-
- S : Storage_Elmt;
-
- begin
- Read_Next (S'Address);
- return S;
- end Read_Next;
-
- -------
- -- H --
- -------
-
- function H (A : Integer_Address) return Address_Range is
- begin
- return Address_Range (A mod Integer_Address (Address_Range'Last));
- end H;
-
- ---------------
- -- Mem_Image --
- ---------------
-
- function Mem_Image (X : Storage_Count) return String is
- Ks : constant Storage_Count := X / 1024;
- Megs : constant Storage_Count := Ks / 1024;
- Buff : String (1 .. 7);
-
- begin
- if Megs /= 0 then
- Ada.Float_Text_IO.Put (Buff, Float (X) / 1024.0 / 1024.0, 2, 0);
- return Buff & " Megabytes";
-
- elsif Ks /= 0 then
- Ada.Float_Text_IO.Put (Buff, Float (X) / 1024.0, 2, 0);
- return Buff & " Kilobytes";
-
- else
- Ada.Integer_Text_IO.Put (Buff (1 .. 4), Integer (X));
- return Buff (1 .. 4) & " Bytes";
- end if;
- end Mem_Image;
-
- -----------
- -- Usage --
- -----------
-
- procedure Usage is
- begin
- New_Line;
- Put ("GNATMEM ");
- Put_Line (Gnat_Version_String);
- Put_Line ("Copyright 1997-2007, Free Software Foundation, Inc.");
- New_Line;
-
- Put_Line ("Usage: gnatmem switches [depth] exename");
- New_Line;
- Put_Line (" depth backtrace depth to take into account, default is"
- & Integer'Image (BT_Depth));
- Put_Line (" exename the name of the executable to be analyzed");
- New_Line;
- Put_Line ("Switches:");
- Put_Line (" -b n same as depth parameter");
- Put_Line (" -i file read the allocation log from specific file");
- Put_Line (" default is gmem.out in the current directory");
- Put_Line (" -m n masks roots with less than n leaks, default is 1");
- Put_Line (" specify 0 to see even released allocation roots");
- Put_Line (" -q quiet, minimum output");
- Put_Line (" -s order sort allocation roots according to an order of");
- Put_Line (" sort criteria");
- GNAT.OS_Lib.OS_Exit (1);
- end Usage;
-
- -----------------------
- -- Process_Arguments --
- -----------------------
-
- procedure Process_Arguments is
- begin
- -- Parse the options first
-
- loop
- case Getopt ("b: dd m: i: q s:") is
- when ASCII.NUL => exit;
-
- when 'b' =>
- begin
- BT_Depth := Natural'Value (Parameter);
- exception
- when Constraint_Error =>
- Usage;
- end;
-
- when 'd' =>
- Dump_Log_Mode := True;
-
- when 'm' =>
- begin
- Minimum_Nb_Leaks := Natural'Value (Parameter);
- exception
- when Constraint_Error =>
- Usage;
- end;
-
- when 'i' =>
- Log_Name := new String'(Parameter);
-
- when 'q' =>
- Quiet_Mode := True;
-
- when 's' =>
- declare
- S : constant String (Sort_Order'Range) := Parameter;
- begin
- for J in Sort_Order'Range loop
- if S (J) = 'n' or else
- S (J) = 'w' or else
- S (J) = 'h'
- then
- Sort_Order (J) := S (J);
- else
- Put_Line ("Invalid sort criteria string.");
- GNAT.OS_Lib.OS_Exit (1);
- end if;
- end loop;
- end;
-
- when others =>
- null;
- end case;
- end loop;
-
- -- Set default log file if -i hasn't been specified
-
- if Log_Name = null then
- Log_Name := new String'("gmem.out");
- end if;
-
- -- Get the optional backtrace length and program name
-
- declare
- Str1 : constant String := GNAT.Command_Line.Get_Argument;
- Str2 : constant String := GNAT.Command_Line.Get_Argument;
-
- begin
- if Str1 = "" then
- Usage;
- end if;
-
- if Str2 = "" then
- Program_Name := new String'(Str1);
- else
- BT_Depth := Natural'Value (Str1);
- Program_Name := new String'(Str2);
- end if;
-
- exception
- when Constraint_Error =>
- Usage;
- end;
-
- -- Ensure presence of executable suffix in Program_Name
-
- declare
- Suffix : String_Access := Get_Executable_Suffix;
- Tmp : String_Access;
-
- begin
- if Suffix.all /= ""
- and then
- Program_Name.all
- (Program_Name.all'Last - Suffix.all'Length + 1 ..
- Program_Name.all'Last) /= Suffix.all
- then
- Tmp := new String'(Program_Name.all & Suffix.all);
- Free (Program_Name);
- Program_Name := Tmp;
- end if;
-
- Free (Suffix);
-
- -- Search the executable on the path. If not found in the PATH, we
- -- default to the current directory. Otherwise, libaddr2line will
- -- fail with an error:
-
- -- (null): Bad address
-
- Tmp := Locate_Exec_On_Path (Program_Name.all);
-
- if Tmp = null then
- Tmp := new String'('.' & Directory_Separator & Program_Name.all);
- end if;
-
- Free (Program_Name);
- Program_Name := Tmp;
- end;
-
- if not Is_Regular_File (Log_Name.all) then
- Put_Line ("Couldn't find " & Log_Name.all);
- GNAT.OS_Lib.OS_Exit (1);
- end if;
-
- if not Gmem_Initialize (Log_Name.all) then
- Put_Line ("File " & Log_Name.all & " is not a gnatmem log file");
- GNAT.OS_Lib.OS_Exit (1);
- end if;
-
- if not Is_Regular_File (Program_Name.all) then
- Put_Line ("Couldn't find " & Program_Name.all);
- end if;
-
- Gmem_A2l_Initialize (Program_Name.all);
-
- exception
- when GNAT.Command_Line.Invalid_Switch =>
- Ada.Text_IO.Put_Line ("Invalid switch : "
- & GNAT.Command_Line.Full_Switch);
- Usage;
- end Process_Arguments;
-
- -- Local variables
-
- Cur_Elmt : Storage_Elmt;
- Buff : String (1 .. 16);
-
--- Start of processing for Gnatmem
-
-begin
- Process_Arguments;
-
- if Dump_Log_Mode then
- Put_Line ("Full dump of dynamic memory operations history");
- Put_Line ("----------------------------------------------");
-
- declare
- function CTime (Clock : Address) return Address;
- pragma Import (C, CTime, "ctime");
-
- Int_T0 : Integer := Integer (T0);
- CTime_Addr : constant Address := CTime (Int_T0'Address);
-
- Buffer : String (1 .. 30);
- for Buffer'Address use CTime_Addr;
-
- begin
- Put_Line ("Log started at T0 =" & Duration'Image (T0) & " ("
- & Buffer (1 .. 24) & ")");
- end;
- end if;
-
- -- Main loop analysing the data generated by the instrumented routines.
- -- For each allocation, the backtrace is kept and stored in a htable
- -- whose entry is the address. For each deallocation, we look for the
- -- corresponding allocation and cancel it.
-
- Main : loop
- Cur_Elmt := Read_Next;
-
- case Cur_Elmt.Elmt is
- when '*' =>
- exit Main;
-
- when 'A' =>
-
- -- Read the corresponding back trace
-
- Tmp_Alloc.Root := Read_BT (BT_Depth);
-
- if Quiet_Mode then
-
- if Nb_Alloc (Tmp_Alloc.Root) = 0 then
- Nb_Root := Nb_Root + 1;
- end if;
-
- Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) + 1);
- Address_HTable.Set (Cur_Elmt.Address, Tmp_Alloc);
-
- elsif Cur_Elmt.Size > 0 then
-
- -- Update global counters if the allocated size is meaningful
-
- Global_Alloc_Size := Global_Alloc_Size + Cur_Elmt.Size;
- Global_Nb_Alloc := Global_Nb_Alloc + 1;
-
- if Global_High_Water_Mark < Global_Alloc_Size then
- Global_High_Water_Mark := Global_Alloc_Size;
- end if;
-
- -- Update the number of allocation root if this is a new one
-
- if Nb_Alloc (Tmp_Alloc.Root) = 0 then
- Nb_Root := Nb_Root + 1;
- end if;
-
- -- Update allocation root specific counters
-
- Set_Alloc_Size (Tmp_Alloc.Root,
- Alloc_Size (Tmp_Alloc.Root) + Cur_Elmt.Size);
-
- Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) + 1);
-
- if High_Water_Mark (Tmp_Alloc.Root) <
- Alloc_Size (Tmp_Alloc.Root)
- then
- Set_High_Water_Mark (Tmp_Alloc.Root,
- Alloc_Size (Tmp_Alloc.Root));
- end if;
-
- -- Associate this allocation root to the allocated address
-
- Tmp_Alloc.Size := Cur_Elmt.Size;
- Address_HTable.Set (Cur_Elmt.Address, Tmp_Alloc);
-
- end if;
-
- when 'D' =>
-
- -- Get the corresponding Dealloc_Size and Root
-
- Tmp_Alloc := Address_HTable.Get (Cur_Elmt.Address);
-
- if Tmp_Alloc.Root = No_Root_Id then
-
- -- There was no prior allocation at this address, something is
- -- very wrong. Mark this allocation root as problematic.
-
- Tmp_Alloc.Root := Read_BT (BT_Depth);
-
- if Nb_Alloc (Tmp_Alloc.Root) = 0 then
- Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) - 1);
- Nb_Wrong_Deall := Nb_Wrong_Deall + 1;
- end if;
-
- else
- -- Update global counters
-
- if not Quiet_Mode then
- Global_Alloc_Size := Global_Alloc_Size - Tmp_Alloc.Size;
- end if;
-
- Global_Nb_Dealloc := Global_Nb_Dealloc + 1;
-
- -- Update allocation root specific counters
-
- if not Quiet_Mode then
- Set_Alloc_Size (Tmp_Alloc.Root,
- Alloc_Size (Tmp_Alloc.Root) - Tmp_Alloc.Size);
- end if;
-
- Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) - 1);
-
- -- Update the number of allocation root if this one disappears
-
- if Nb_Alloc (Tmp_Alloc.Root) = 0
- and then Minimum_Nb_Leaks > 0 then
- Nb_Root := Nb_Root - 1;
- end if;
-
- -- Deassociate the deallocated address
-
- Address_HTable.Remove (Cur_Elmt.Address);
- end if;
-
- when others =>
- raise Program_Error;
- end case;
-
- if Dump_Log_Mode then
- case Cur_Elmt.Elmt is
- when 'A' =>
- Put ("ALLOC");
- Int_IO.Put (Buff (1 .. 16), Integer (Cur_Elmt.Address), 16);
- Put (Buff);
- Int_IO.Put (Buff (1 .. 8), Integer (Cur_Elmt.Size));
- Put (Buff (1 .. 8) & " bytes at moment T0 +");
- Put_Line (Duration'Image (Cur_Elmt.Timestamp - T0));
-
- when 'D' =>
- Put ("DEALL");
- Int_IO.Put (Buff (1 .. 16), Integer (Cur_Elmt.Address), 16);
- Put (Buff);
- Put_Line (" at moment T0 +"
- & Duration'Image (Cur_Elmt.Timestamp - T0));
- when others =>
- raise Program_Error;
- end case;
-
- Print_BT (Tmp_Alloc.Root);
- end if;
-
- end loop Main;
-
- -- Print out general information about overall allocation
-
- if not Quiet_Mode then
- Put_Line ("Global information");
- Put_Line ("------------------");
-
- Put (" Total number of allocations :");
- Ada.Integer_Text_IO.Put (Global_Nb_Alloc, 4);
- New_Line;
-
- Put (" Total number of deallocations :");
- Ada.Integer_Text_IO.Put (Global_Nb_Dealloc, 4);
- New_Line;
-
- Put_Line (" Final Water Mark (non freed mem) :"
- & Mem_Image (Global_Alloc_Size));
- Put_Line (" High Water Mark :"
- & Mem_Image (Global_High_Water_Mark));
- New_Line;
- end if;
-
- -- Print out the back traces corresponding to potential leaks in order
- -- greatest number of non-deallocated allocations.
-
- Print_Back_Traces : declare
- type Root_Array is array (Natural range <>) of Root_Id;
- type Access_Root_Array is access Root_Array;
-
- Leaks : constant Access_Root_Array :=
- new Root_Array (0 .. Nb_Root);
- Leak_Index : Natural := 0;
-
- Bogus_Dealls : constant Access_Root_Array :=
- new Root_Array (1 .. Nb_Wrong_Deall);
- Deall_Index : Natural := 0;
- Nb_Alloc_J : Natural := 0;
-
- procedure Move (From : Natural; To : Natural);
- function Lt (Op1, Op2 : Natural) return Boolean;
- package Root_Sort is new GNAT.Heap_Sort_G (Move, Lt);
-
- ----------
- -- Move --
- ----------
-
- procedure Move (From : Natural; To : Natural) is
- begin
- Leaks (To) := Leaks (From);
- end Move;
-
- --------
- -- Lt --
- --------
-
- function Lt (Op1, Op2 : Natural) return Boolean is
-
- function Apply_Sort_Criterion (S : Character) return Integer;
- -- Applies a specific sort criterion; returns -1, 0 or 1 if Op1 is
- -- smaller than, equal, or greater than Op2 according to criterion.
-
- --------------------------
- -- Apply_Sort_Criterion --
- --------------------------
-
- function Apply_Sort_Criterion (S : Character) return Integer is
- LOp1, LOp2 : Integer;
-
- begin
- case S is
- when 'n' =>
- LOp1 := Nb_Alloc (Leaks (Op1));
- LOp2 := Nb_Alloc (Leaks (Op2));
-
- when 'w' =>
- LOp1 := Integer (Alloc_Size (Leaks (Op1)));
- LOp2 := Integer (Alloc_Size (Leaks (Op2)));
-
- when 'h' =>
- LOp1 := Integer (High_Water_Mark (Leaks (Op1)));
- LOp2 := Integer (High_Water_Mark (Leaks (Op2)));
-
- when others =>
- return 0; -- Can't actually happen
- end case;
-
- if LOp1 < LOp2 then
- return -1;
- elsif LOp1 > LOp2 then
- return 1;
- else
- return 0;
- end if;
-
- exception
- when Constraint_Error =>
- return 0;
- end Apply_Sort_Criterion;
-
- -- Local Variables
-
- Result : Integer;
-
- -- Start of processing for Lt
-
- begin
- for S in Sort_Order'Range loop
- Result := Apply_Sort_Criterion (Sort_Order (S));
- if Result = -1 then
- return False;
- elsif Result = 1 then
- return True;
- end if;
- end loop;
- return False;
- end Lt;
-
- -- Start of processing for Print_Back_Traces
-
- begin
- -- Transfer all the relevant Roots in the Leaks and a Bogus_Deall arrays
-
- Tmp_Alloc.Root := Get_First;
- while Tmp_Alloc.Root /= No_Root_Id loop
- if Nb_Alloc (Tmp_Alloc.Root) = 0 and then Minimum_Nb_Leaks > 0 then
- null;
-
- elsif Nb_Alloc (Tmp_Alloc.Root) < 0 then
- Deall_Index := Deall_Index + 1;
- Bogus_Dealls (Deall_Index) := Tmp_Alloc.Root;
-
- else
- Leak_Index := Leak_Index + 1;
- Leaks (Leak_Index) := Tmp_Alloc.Root;
- end if;
-
- Tmp_Alloc.Root := Get_Next;
- end loop;
-
- -- Print out wrong deallocations
-
- if Nb_Wrong_Deall > 0 then
- Put_Line ("Releasing deallocated memory at :");
- if not Quiet_Mode then
- Put_Line ("--------------------------------");
- end if;
-
- for J in 1 .. Bogus_Dealls'Last loop
- Print_BT (Bogus_Dealls (J), Short => Quiet_Mode);
- New_Line;
- end loop;
- end if;
-
- -- Print out all allocation Leaks
-
- if Leak_Index > 0 then
-
- -- Sort the Leaks so that potentially important leaks appear first
-
- Root_Sort.Sort (Leak_Index);
-
- for J in 1 .. Leak_Index loop
- Nb_Alloc_J := Nb_Alloc (Leaks (J));
-
- if Nb_Alloc_J >= Minimum_Nb_Leaks then
- if Quiet_Mode then
- if Nb_Alloc_J = 1 then
- Put_Line (" 1 leak at :");
- else
- Put_Line (Integer'Image (Nb_Alloc_J) & " leaks at :");
- end if;
-
- else
- Put_Line ("Allocation Root #" & Integer'Image (J));
- Put_Line ("-------------------");
-
- Put (" Number of non freed allocations :");
- Ada.Integer_Text_IO.Put (Nb_Alloc_J, 4);
- New_Line;
-
- Put_Line
- (" Final Water Mark (non freed mem) :"
- & Mem_Image (Alloc_Size (Leaks (J))));
-
- Put_Line
- (" High Water Mark :"
- & Mem_Image (High_Water_Mark (Leaks (J))));
-
- Put_Line (" Backtrace :");
- end if;
-
- Print_BT (Leaks (J), Short => Quiet_Mode);
- New_Line;
- end if;
- end loop;
- end if;
- end Print_Back_Traces;
-end Gnatmem;