michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: package TraceMalloc; michael@0: michael@0: use strict; michael@0: michael@0: # Read in the type inference file and construct a network that we can michael@0: # use to match stack prefixes to types. michael@0: sub init_type_inference($) { michael@0: my ($file) = @_; michael@0: michael@0: $::Fingerprints = { }; michael@0: michael@0: open(TYPES, "<$file") || die "unable to open $::opt_types, $!"; michael@0: michael@0: TYPE: while () { michael@0: next TYPE unless /<(.*)>/; michael@0: my $type = $1; michael@0: michael@0: my $link = \%::Fingerprints; michael@0: michael@0: FRAME: while () { michael@0: chomp; michael@0: last FRAME if /^$/; michael@0: michael@0: my $next = $link->{$_}; michael@0: if (! $next) { michael@0: $next = $link->{$_} = {}; michael@0: } michael@0: $link = $next; michael@0: } michael@0: michael@0: $link->{'#type#'} = $type; michael@0: michael@0: last TYPE if eof; michael@0: } michael@0: } michael@0: michael@0: # Infer the type, trying to find the most specific type possible. michael@0: sub infer_type($) { michael@0: my ($stack) = @_; michael@0: michael@0: my $link = \%::Fingerprints; michael@0: my $last; michael@0: my $type = 'void*'; michael@0: FRAME: foreach my $frame (@$stack) { michael@0: last FRAME unless $link; michael@0: michael@0: $frame =~ s/\[.*\]$//; # ignore exact addresses, as they'll drift michael@0: michael@0: $last = $link; michael@0: michael@0: # michael@0: # Remember this type, but keep going. We use the longest match michael@0: # we find, but substacks of longer matches will also match. michael@0: # michael@0: if ($last->{'#type#'}) { michael@0: $type = $last->{'#type#'}; michael@0: } michael@0: michael@0: $link = $link->{$frame}; michael@0: michael@0: if (! $link) { michael@0: CHILD: foreach my $child (keys %$last) { michael@0: next CHILD unless $child =~ /^~/; michael@0: michael@0: $child =~ s/^~//; michael@0: michael@0: if ($frame =~ $child) { michael@0: $link = $last->{'~' . $child}; michael@0: last CHILD; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return $type; michael@0: } michael@0: michael@0: michael@0: #---------------------------------------------------------------------- michael@0: # michael@0: # Read in the output a trace malloc's dump. michael@0: # michael@0: sub read { michael@0: my ($callback, $noslop) = @_; michael@0: michael@0: OBJECT: while (<>) { michael@0: # e.g., 0x0832FBD0 (80) michael@0: next OBJECT unless /^0x(\S+) <(.*)> \((\d+)\)/; michael@0: my ($addr, $type, $size) = (hex $1, $2, $3); michael@0: michael@0: my $object = { 'type' => $type, 'size' => $size }; michael@0: michael@0: # Record the object's slots michael@0: my @slots; michael@0: michael@0: SLOT: while (<>) { michael@0: # e.g., 0x00000000 michael@0: last SLOT unless /^\t0x(\S+)/; michael@0: my $value = hex $1; michael@0: michael@0: # Ignore low bits, unless they've specified --noslop michael@0: $value &= ~0x7 unless $noslop; michael@0: michael@0: $slots[$#slots + 1] = $value; michael@0: } michael@0: michael@0: $object->{'slots'} = \@slots; michael@0: michael@0: # Record the stack by which the object was allocated michael@0: my @stack; michael@0: michael@0: while (/^(.*)\[(.*) \+0x(\S+)\]$/) { michael@0: # e.g., _dl_debug_message[/lib/ld-linux.so.2 +0x0000B858] michael@0: my ($func, $lib, $off) = ($1, $2, hex $3); michael@0: michael@0: chomp; michael@0: $stack[$#stack + 1] = $_; michael@0: michael@0: $_ = <>; michael@0: } michael@0: michael@0: $object->{'stack'} = \@stack; michael@0: michael@0: $object->{'type'} = infer_type(\@stack) michael@0: if $object->{'type'} eq 'void*'; michael@0: michael@0: &$callback($object) if $callback; michael@0: michael@0: # Gotta check EOF explicitly... michael@0: last OBJECT if eof; michael@0: } michael@0: } michael@0: michael@0: 1; michael@0: __END__ michael@0: michael@0: =head1 NAME michael@0: michael@0: TraceMalloc - Perl routines to deal with output from ``trace malloc'' michael@0: and the Boehm GC michael@0: michael@0: =head1 SYNOPSIS michael@0: michael@0: use TraceMalloc; michael@0: michael@0: TraceMalloc::init_type_inference("types.dat"); michael@0: TraceMalloc::read(0); michael@0: michael@0: =head1 DESCRIPTION michael@0: michael@0: =head1 EXAMPLES michael@0: michael@0: =cut