diff --git a/tools/handlertree.pl b/tools/handlertree.pl new file mode 100644 index 0000000000..ff5c06b1d9 --- /dev/null +++ b/tools/handlertree.pl @@ -0,0 +1,140 @@ +#!/usr/bin/perl -w +# +# handlertree.pl +# ~~~~~~~~~~~~~~ +# A tool for post-processing the debug output generated by Asio-based programs +# to print the tree of handlers that resulted in some specified handler ids. +# Programs write this output to the standard error stream when compiled with +# the define `BOOST_ASIO_ENABLE_HANDLER_TRACKING'. +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +use strict; + +my %target_handlers = (); +my @cached_output = (); +my %outstanding_handlers = (); +my %running_handlers = (); + +#------------------------------------------------------------------------------- +# Build the initial list of target handlers from the command line arguments. + +sub build_initial_target_handlers() +{ + for my $handler (@ARGV) + { + $target_handlers{$handler} = 1; + } +} + +#------------------------------------------------------------------------------- +# Parse the debugging output and cache the handler tracking lines. + +sub parse_debug_output() +{ + while (my $line = ) + { + chomp($line); + + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + push(@cached_output, $line); + } + } +} + +#------------------------------------------------------------------------------- +# Iterate over the cached output in revese and build a hash of all target +# handlers' ancestors. + +sub build_target_handler_tree() +{ + my $i = scalar(@cached_output) - 1; + while ($i >= 0) + { + my $line = $cached_output[$i]; + + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + my $action = $2; + + # Handler creation. + if ($action =~ /^([0-9]+)\*([0-9]+)$/) + { + if ($1 ne "0" and exists($target_handlers{$2})) + { + $target_handlers{$1} = 1; + } + } + } + + --$i; + } +} + +#------------------------------------------------------------------------------- +# Print out all handler tracking records associated with the target handlers. + +sub print_target_handler_records() +{ + for my $line (@cached_output) + { + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + my $action = $2; + + # Handler location. + if ($action =~ /^([0-9]+)\^([0-9]+)$/) + { + print("$line\n") if ($1 eq "0" or exists($target_handlers{$1})) and exists($target_handlers{$2}); + } + + # Handler creation. + if ($action =~ /^([0-9]+)\*([0-9]+)$/) + { + print("$1, $2, $line\n") if ($1 eq "0" or exists($target_handlers{$1})) and exists($target_handlers{$2}); + } + + # Begin handler invocation. + elsif ($action =~ /^>([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + + # End handler invocation. + elsif ($action =~ /^<([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + + # Handler threw exception. + elsif ($action =~ /^!([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + + # Handler was destroyed without being invoked. + elsif ($action =~ /^~([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + + # Operation associated with a handler. + elsif ($action =~ /^\.([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + } + } +} + +#------------------------------------------------------------------------------- + +build_initial_target_handlers(); +parse_debug_output(); +build_target_handler_tree(); +print_target_handler_records();