using System.Globalization; using System.Globalization.NumberStyles; using Nemerle.Collections; using Nemerle.IO; variant Address { | A {a : string; s : int;} | D {a : string;} } class Alloc { private static mutable locs : Hashtable [string, string]; private static mutable binary : string; public size : int; private memory : string; private trace : array [string]; public this (memory : string, trace : array [string], size : int) { this.memory = memory; this.trace = trace; this.size = size; } public this (memory : string, trace : array [string]) { this.memory = memory; this.trace = trace; this.size = 0; } public static init (binary : string) : void { locs = Hashtable (); Alloc.binary = binary; } static get_location (addr : string) : string { mutable run = System.Diagnostics.Process (); run.StartInfo.FileName = sprintf ("addr2line -e %s %s", binary, addr); run.StartInfo.RedirectStandardOutput = true; run.StartInfo.UseShellExecute = false; def _ = run.Start (); run.StandardOutput.ReadLine () } static find_location (addr : string) : string { match (locs.Get (addr)){ | None => get_location (addr); | Some (s) => s; } } static print_location (addr : string, more_tabs : bool) : void { if (more_tabs) printf ("\t\t") else (); printf ("\t%s\n", find_location (addr)) } public static print_trace (trace : array [string]) : void { for (mutable i = 0; i < trace.Length; i = i + 1){ print_location (trace[i], i != 0); } } public print () : void { printf ("%s\t%d", memory, size); Alloc.print_trace (trace) } } class NTrace { private static mutable allocs : Hashtable [string, Alloc]; static usage () : void { printf ("Usage: ntrace binary data\n"); System.Environment.Exit (1) } static init_allocs () : void { allocs = Hashtable () } static get_locations (s : string) : array [string] { def f = s.IndexOf ('['); def l = s.IndexOf (']'); def delim = array [',']; (s.Substring (f + 1, l - f - 1)).Split (delim) } static get_address (s : string) : Address { def i = s.LastIndexOfAny (array ['+', '-', '<', '>']); def j = s.IndexOf (' ', i + 2); if (s[i] == '+' || s[i] == '>'){ A (s.Substring (i + 2, 9), System.Int32.Parse (s.Substring (j + 3), AllowHexSpecifier)) } else D (s.Substring (i + 2, 9)) } static put_alloc (locs : array [string], mem : string, size : int) : void { try { allocs.Add (mem, Alloc (mem, locs, size)) } catch { _ : System.ArgumentException => printf ("Double alloc to %s of size %d\n", mem, size); Alloc.print_trace (locs) } } static put_dealloc (locs : array [string], mem : string) : void { if (allocs.Contains (mem)) allocs.Remove (mem) else { printf ("Memory was never allocated: %s\n", mem); Alloc.print_trace (locs) } } static process_line (s : string) : void { def locs = get_locations (s); match (get_address (s)){ | A (s, d) => put_alloc (locs, s, d); | D (s) => put_dealloc (locs, s); } } static read_data (fname : string) : void { def fp = System.IO.File.OpenText (fname); mutable str = fp.ReadLine (); while (str != null){ if (str[0] == '@') process_line (str) else (); str = fp.ReadLine (); }; fp.Close () } static add_leak (_ : string, a : Alloc, d : int) : int { if (d == 0){ printf ("\nMemory not freed:\n"); printf ("-----------------\n"); printf (" Address\tSize\tCaller\n") } else (); a.print (); d + a.size } static trace_leaks () : void { def d = allocs.Fold (0, add_leak); if (d != 0) printf ("Total memory not freed: %d\n", d) else printf ("No memory leaks.\n"); } public static Main (args : array [string]) : void { def count = args.Length; if (count != 2) usage () else (); def binary = args[0]; def data = args[1]; Alloc.init (binary); init_allocs (); try { read_data (data) } catch { e : System.Exception => printf ("While reading file %s: %s\n", data, e.Message); System.Environment.Exit (1) }; trace_leaks () } }