# The contents of this file are subject to the Mozilla Public # License Version 1.1 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr # implied. See the License for the specific language governing # rights and limitations under the License. # # The Original Code is TraceMalloc.pm, released Nov 27, 2000. # # The Initial Developer of the Original Code is Netscape # Communications Corporation. Portions created by Netscape are # Copyright (C) 2000 Netscape Communications Corporation. All # Rights Reserved. # # Contributor(s): # Chris Waterson # package TraceMalloc; use strict; # Read in the type inference file and construct a network that we can # use to match stack prefixes to types. sub init_type_inference($) { my ($file) = @_; $::Fingerprints = { }; open(TYPES, "<$file") || die "unable to open $::opt_types, $!"; TYPE: while () { next TYPE unless /<(.*)>/; my $type = $1; my $link = \%::Fingerprints; FRAME: while () { chomp; last FRAME if /^$/; my $next = $link->{$_}; if (! $next) { $next = $link->{$_} = {}; } $link = $next; } $link->{'#type#'} = $type; last TYPE if eof; } } # Infer the type, trying to find the most specific type possible. sub infer_type($) { my ($stack) = @_; my $link = \%::Fingerprints; my $last; FRAME: foreach my $frame (@$stack) { last FRAME unless $link; $frame =~ s/\[.*\]$//; # ignore exact addresses, as they'll drift $last = $link; $link = $link->{$frame}; } if ($last && $last->{'#type#'}) { return $last->{'#type#'}; } else { return 'void*'; } } #---------------------------------------------------------------------- # # Read in the output a trace malloc's dump. # sub read { my ($callback, $noslop) = @_; OBJECT: while (<>) { # e.g., 0x0832FBD0 (80) next OBJECT unless /^0x(\S+) <(.*)> \((\d+)\)/; my ($addr, $type, $size) = (hex $1, $2, $3); my $object = { 'type' => $type, 'size' => $size }; # Record the object's slots my @slots; SLOT: while (<>) { # e.g., 0x00000000 last SLOT unless /^\t0x(\S+)/; my $value = hex $1; # Ignore low bits, unless they've specified --noslop $value &= ~0x7 unless $noslop; $slots[$#slots + 1] = $value; } $object->{'slots'} = \@slots; # Record the stack by which the object was allocated my @stack; while (/^(.*)\[(.*) \+0x(\S+)\]$/) { # e.g., _dl_debug_message[/lib/ld-linux.so.2 +0x0000B858] my ($func, $lib, $off) = ($1, $2, hex $3); chomp; $stack[$#stack + 1] = $_; $_ = <>; } $object->{'stack'} = \@stack; $object->{'type'} = infer_type(\@stack) if $object->{'type'} eq 'void*'; &$callback($object) if $callback; # Gotta check EOF explicitly... last OBJECT if eof; } } 1; __END__ =head1 NAME TraceMalloc - Perl routines to deal with output from ``trace malloc'' and the Boehm GC =head1 SYNOPSIS use TraceMalloc; TraceMalloc::init_type_inference("types.dat"); TraceMalloc::read(0); =head1 DESCRIPTION =head1 EXAMPLES =cut