⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 strace-graph

📁 linux进程跟踪的工具和源代码
💻
字号:
#!/usr/bin/perl# This script processes strace -f output.  It displays a graph of invoked# subprocesses, and is useful for finding out what complex commands do.# You will probably want to invoke strace with -q as well, and with# -s 100 to get complete filenames.# The script can also handle the output with strace -t, -tt, or -ttt.# It will add elapsed time for each process in that case.# This script is Copyright (C) 1998 by Richard Braakman <dark@xs4all.nl>.# Redistribution and use in source and binary forms, with or without# modification, are permitted provided that the following conditions# are met:# 1. Redistributions of source code must retain the above copyright#    notice, this list of conditions and the following disclaimer.# 2. Redistributions in binary form must reproduce the above copyright#    notice, this list of conditions and the following disclaimer in the#    documentation and/or other materials provided with the distribution.# 3. The name of the author may not be used to endorse or promote products#    derived from this software without specific prior written permission.## THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.##	$Id: strace-graph,v 1.2 1999/08/30 23:26:53 wichert Exp $my %unfinished;# Scales for strace slowdown.  Make configurable!my $scale_factor = 3.5;while (<>) {    my ($pid, $call, $args, $result, $time);    chop;    s/^(\d+)\s+//;    $pid = $1;    if (s/^(\d\d):(\d\d):(\d\d)(?:\.(\d\d\d\d\d\d))? //) {	$time = $1 * 3600 + $2 * 60 + $3;	if (defined $4) {	    $time = $time + $4 / 1000000;	    $floatform = 1;	}    } elsif (s/^(\d+)\.(\d\d\d\d\d\d) //) {	$time = $1 + ($2 / 1000000);	$floatform = 1;    }    if (s/ <unfinished ...>$//) {	$unfinished{$pid} = $_;	next;    }    if (s/^<... \S+ resumed> //) {	unless (exists $unfinished{$pid}) {	    print STDERR "$0: $ARGV: cannot find start of resumed call on line $.";	    next;	}	$_ = $unfinished{$pid} . $_;	delete $unfinished{$pid};    }    if (/^--- SIG(\S+) \(.*\) ---$/) {	# $pid received signal $1	# currently we don't do anything with this	next;    }    if (/^\+\+\+ killed by SIG(\S+) \+\+\+$/) {	# $pid received signal $1	handle_killed($pid, $time);	next;    }    ($call, $args, $result) = /(\S+)\((.*)\)\s+= (.*)$/;    unless (defined $result) {	print STDERR "$0: $ARGV: $.: cannot parse line.\n";	next;    }    handle_trace($pid, $call, $args, $result, $time);}display_trace();exit 0;sub parse_str {    my ($in) = @_;    my $result = "";    while (1) {	if ($in =~ s/^\\(.)//) {	    $result .= $1;	} elsif ($in =~ s/^\"//) {	    if ($in =~ s/^\.\.\.//) {		return ("$result...", $in);	    }	    return ($result, $in);	} elsif ($in =~ s/([^\\\"]*)//) {	    $result .= $1;	} else {	    return (undef, $in);	}    }}    sub parse_one {    my ($in) = @_;    if ($in =~ s/^\"//) {	($tmp, $in) = parse_str($in);	if (not defined $tmp) {	    print STDERR "$0: $ARGV: $.: cannot parse string.\n";	    return (undef, $in);	}	return ($tmp, $in);    } elsif ($in =~ s/^0x(\x+)//) {	return (hex $1, $in);    } elsif ($in =~ s/^(\d+)//) {	return (int $1, $in);    } else {	print STDERR "$0: $ARGV: $.: unrecognized element.\n";	return (undef, $in);    }}sub parseargs {    my ($in) = @_;    my @args = ();    my $tmp;    while (length $in) {	if ($in =~ s/^\[//) {	    my @subarr = ();	    if ($in =~ s,^/\* (\d+) vars \*/\],,) {		push @args, $1;	    } else {		while ($in !~ s/^\]//) {		    ($tmp, $in) = parse_one($in);		    defined $tmp or return undef;		    push @subarr, $tmp;		    unless ($in =~ /^\]/ or $in =~ s/^, //) {			print STDERR "$0: $ARGV: $.: missing comma in array.\n";			return undef;		    }		    if ($in =~ s/^\.\.\.//) {			push @subarr, "...";		    }		}		push @args, \@subarr;	    }	} elsif ($in =~ s/^\{//) {	    my %subhash = ();	    while ($in !~ s/^\}//) {		my $key;		unless ($in =~ s/^(\w+)=//) {		    print STDERR "$0: $ARGV: $.: struct field expected.\n";		    return undef;		}		$key = $1;		($tmp, $in) = parse_one($in);		defined $tmp or return undef;		$subhash{$key} = $tmp;		unless ($in =~ s/, //) {		    print STDERR "$0: $ARGV: $.: missing comma in struct.\n";		    return undef;		}	    }	    push @args, \%subhash;	} else {	    ($tmp, $in) = parse_one($in);	    defined $tmp or return undef;	    push @args, $tmp;	}	unless (length($in) == 0 or $in =~ s/^, //) {	    print STDERR "$0: $ARGV: $.: missing comma.\n";	    return undef;	}	        }    return @args;}	    my $depth = "";# process info, indexed by pid.# fields: #    parent         pid number#    seq            forks and execs for this pid, in sequence  (array) #  filename and argv (from latest exec)#  basename (derived from filename)# argv[0] is modified to add the basename if it differs from the 0th argument.my %pr;sub handle_trace {    my ($pid, $call, $args, $result, $time) = @_;    my $p;    if (defined $time and not defined $pr{$pid}{start}) {	$pr{$pid}{start} = $time;    }    if ($call eq 'execve') {	return if $result != 0;	my ($filename, $argv) = parseargs($args);	($basename) = $filename =~ m/([^\/]*)$/;	if ($basename ne $$argv[0]) {	    $$argv[0] = "$basename($$argv[0])";        }	my $seq = $pr{$pid}{seq};	$seq = [] if not defined $seq;	push @$seq, ['EXEC', $filename, $argv];	$pr{$pid}{seq} = $seq;    } elsif ($call eq 'fork') {	return if $result == 0;	my $seq = $pr{$pid}{seq};	$seq = [] if not defined $seq;	push @$seq, ['FORK', $result];	$pr{$pid}{seq} = $seq;	$pr{$result}{parent} = $pid;    } elsif ($call eq '_exit') {	$pr{$pid}{end} = $time if defined $time;    }}sub handle_killed {    my ($pid, $time) = @_;    $pr{$pid}{end} = $time if defined $time;}sub straight_seq {    my ($pid) = @_;    my $seq = $pr{$pid}{seq};    for $elem (@$seq) {	if ($$elem[0] eq 'EXEC') {	    my $argv = $$elem[2];	    print "$$elem[0] $$elem[1] @$argv\n";	} elsif ($$elem[0] eq 'FORK') {	    print "$$elem[0] $$elem[1]\n";	} else {	    print "$$elem[0]\n";	}    }}sub first_exec {    my ($pid) = @_;    my $seq = $pr{$pid}{seq};    for $elem (@$seq) {	if ($$elem[0] eq 'EXEC') {	    return $elem;	}    }    return undef;}sub display_pid_trace {    my ($pid, $lead) = @_;    my $i = 0;    my @seq = @{$pr{$pid}{seq}};    my $elapsed;    if (not defined first_exec($pid)) {	unshift @seq, ['EXEC', '', ['(anon)'] ];    }    if (defined $pr{$pid}{start} and defined $pr{$pid}{end}) {	$elapsed = $pr{$pid}{end} - $pr{$pid}{start};	$elapsed /= $scale_factor;	if ($floatform) {	    $elapsed = sprintf("%0.02f", $elapsed);	} else {	    $elapsed = int $elapsed;	}    }    for $elem (@seq) {	$i++;	if ($$elem[0] eq 'EXEC') {	    my $argv = $$elem[2];	    if (defined $elapsed) {		print "$lead [$elapsed] @$argv\n";		undef $elapsed;	    } else {		print "$lead @$argv\n";	    }	} elsif ($$elem[0] eq 'FORK') {	    if ($i == 1) {                if ($lead =~ /-$/) { 		    display_pid_trace($$elem[1], "$lead--+--");                } else { 		    display_pid_trace($$elem[1], "$lead  +--");                }	    } elsif ($i == @seq) {		display_pid_trace($$elem[1], "$lead  `--");	    } else {		display_pid_trace($$elem[1], "$lead  +--");	    }	}	if ($i == 1) {	    $lead =~ s/\`--/   /g;	    $lead =~ s/-/ /g;	    $lead =~ s/\+/|/g;	}    }}sub display_trace {    my ($startpid) = @_;    $startpid = (keys %pr)[0];    while ($pr{$startpid}{parent}) {	$startpid = $pr{$startpid}{parent};    }    display_pid_trace($startpid, "");}    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -