xref: /aosp_15_r20/external/strace/strace-graph (revision cf84ac9a129d8ea9952db616b4e9b904c4bdde56)
1*cf84ac9aSAndroid Build Coastguard Worker#!/usr/bin/perl
2*cf84ac9aSAndroid Build Coastguard Worker
3*cf84ac9aSAndroid Build Coastguard Worker# This script processes strace -f output.  It displays a graph of invoked
4*cf84ac9aSAndroid Build Coastguard Worker# subprocesses, and is useful for finding out what complex commands do.
5*cf84ac9aSAndroid Build Coastguard Worker
6*cf84ac9aSAndroid Build Coastguard Worker# You will probably want to invoke strace with -q as well, and with
7*cf84ac9aSAndroid Build Coastguard Worker# -s 100 to get complete filenames.
8*cf84ac9aSAndroid Build Coastguard Worker
9*cf84ac9aSAndroid Build Coastguard Worker# The script can also handle the output with strace -t, -tt, or -ttt.
10*cf84ac9aSAndroid Build Coastguard Worker# It will add elapsed time for each process in that case.
11*cf84ac9aSAndroid Build Coastguard Worker
12*cf84ac9aSAndroid Build Coastguard Worker# Copyright (c) 1998 by Richard Braakman <[email protected]>.
13*cf84ac9aSAndroid Build Coastguard Worker# Copyright (c) 1998-2017 The strace developers.
14*cf84ac9aSAndroid Build Coastguard Worker
15*cf84ac9aSAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without
16*cf84ac9aSAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions
17*cf84ac9aSAndroid Build Coastguard Worker# are met:
18*cf84ac9aSAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright
19*cf84ac9aSAndroid Build Coastguard Worker#    notice, this list of conditions and the following disclaimer.
20*cf84ac9aSAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright
21*cf84ac9aSAndroid Build Coastguard Worker#    notice, this list of conditions and the following disclaimer in the
22*cf84ac9aSAndroid Build Coastguard Worker#    documentation and/or other materials provided with the distribution.
23*cf84ac9aSAndroid Build Coastguard Worker# 3. The name of the author may not be used to endorse or promote products
24*cf84ac9aSAndroid Build Coastguard Worker#    derived from this software without specific prior written permission.
25*cf84ac9aSAndroid Build Coastguard Worker#
26*cf84ac9aSAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27*cf84ac9aSAndroid Build Coastguard Worker# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28*cf84ac9aSAndroid Build Coastguard Worker# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29*cf84ac9aSAndroid Build Coastguard Worker# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30*cf84ac9aSAndroid Build Coastguard Worker# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31*cf84ac9aSAndroid Build Coastguard Worker# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32*cf84ac9aSAndroid Build Coastguard Worker# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33*cf84ac9aSAndroid Build Coastguard Worker# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34*cf84ac9aSAndroid Build Coastguard Worker# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35*cf84ac9aSAndroid Build Coastguard Worker# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36*cf84ac9aSAndroid Build Coastguard Worker
37*cf84ac9aSAndroid Build Coastguard Workeruse strict;
38*cf84ac9aSAndroid Build Coastguard Workeruse warnings;
39*cf84ac9aSAndroid Build Coastguard Worker
40*cf84ac9aSAndroid Build Coastguard Workermy %unfinished;
41*cf84ac9aSAndroid Build Coastguard Workermy $floatform;
42*cf84ac9aSAndroid Build Coastguard Worker
43*cf84ac9aSAndroid Build Coastguard Worker# Scales for strace slowdown.  Make configurable!
44*cf84ac9aSAndroid Build Coastguard Workermy $scale_factor = 3.5;
45*cf84ac9aSAndroid Build Coastguard Workermy %running_fqname;
46*cf84ac9aSAndroid Build Coastguard Worker
47*cf84ac9aSAndroid Build Coastguard Workerwhile (<>) {
48*cf84ac9aSAndroid Build Coastguard Worker    my ($pid, $call, $args, $result, $time, $time_spent);
49*cf84ac9aSAndroid Build Coastguard Worker    chop;
50*cf84ac9aSAndroid Build Coastguard Worker    $floatform = 0;
51*cf84ac9aSAndroid Build Coastguard Worker
52*cf84ac9aSAndroid Build Coastguard Worker    s/^(\d+)\s+//;
53*cf84ac9aSAndroid Build Coastguard Worker    $pid = $1;
54*cf84ac9aSAndroid Build Coastguard Worker
55*cf84ac9aSAndroid Build Coastguard Worker    if (s/^(\d\d):(\d\d):(\d\d)(?:\.(\d\d\d\d\d\d))? //) {
56*cf84ac9aSAndroid Build Coastguard Worker	$time = $1 * 3600 + $2 * 60 + $3;
57*cf84ac9aSAndroid Build Coastguard Worker	if (defined $4) {
58*cf84ac9aSAndroid Build Coastguard Worker	    $time = $time + $4 / 1000000;
59*cf84ac9aSAndroid Build Coastguard Worker	    $floatform = 1;
60*cf84ac9aSAndroid Build Coastguard Worker	}
61*cf84ac9aSAndroid Build Coastguard Worker    } elsif (s/^(\d+)\.(\d\d\d\d\d\d) //) {
62*cf84ac9aSAndroid Build Coastguard Worker	$time = $1 + ($2 / 1000000);
63*cf84ac9aSAndroid Build Coastguard Worker	$floatform = 1;
64*cf84ac9aSAndroid Build Coastguard Worker    }
65*cf84ac9aSAndroid Build Coastguard Worker
66*cf84ac9aSAndroid Build Coastguard Worker    if (s/ <unfinished ...>$//) {
67*cf84ac9aSAndroid Build Coastguard Worker	$unfinished{$pid} = $_;
68*cf84ac9aSAndroid Build Coastguard Worker	next;
69*cf84ac9aSAndroid Build Coastguard Worker    }
70*cf84ac9aSAndroid Build Coastguard Worker
71*cf84ac9aSAndroid Build Coastguard Worker    if (s/^<... \S+ resumed> //) {
72*cf84ac9aSAndroid Build Coastguard Worker	unless (exists $unfinished{$pid}) {
73*cf84ac9aSAndroid Build Coastguard Worker	    print STDERR "$0: $ARGV: cannot find start of resumed call on line $.";
74*cf84ac9aSAndroid Build Coastguard Worker	    next;
75*cf84ac9aSAndroid Build Coastguard Worker	}
76*cf84ac9aSAndroid Build Coastguard Worker	$_ = $unfinished{$pid} . $_;
77*cf84ac9aSAndroid Build Coastguard Worker	delete $unfinished{$pid};
78*cf84ac9aSAndroid Build Coastguard Worker    }
79*cf84ac9aSAndroid Build Coastguard Worker
80*cf84ac9aSAndroid Build Coastguard Worker    if (/^--- SIG(\S+) (.*) ---$/) {
81*cf84ac9aSAndroid Build Coastguard Worker	# $pid received signal $1
82*cf84ac9aSAndroid Build Coastguard Worker	# currently we don't do anything with this
83*cf84ac9aSAndroid Build Coastguard Worker	next;
84*cf84ac9aSAndroid Build Coastguard Worker    }
85*cf84ac9aSAndroid Build Coastguard Worker
86*cf84ac9aSAndroid Build Coastguard Worker    if (/^\+\+\+ killed by SIG(\S+) \+\+\+$/) {
87*cf84ac9aSAndroid Build Coastguard Worker	# $pid received signal $1
88*cf84ac9aSAndroid Build Coastguard Worker	handle_killed($pid, $time);
89*cf84ac9aSAndroid Build Coastguard Worker	next;
90*cf84ac9aSAndroid Build Coastguard Worker    }
91*cf84ac9aSAndroid Build Coastguard Worker
92*cf84ac9aSAndroid Build Coastguard Worker    if (/^\+\+\+ exited with (\d+) \+\+\+$/) {
93*cf84ac9aSAndroid Build Coastguard Worker	# $pid exited $1
94*cf84ac9aSAndroid Build Coastguard Worker	# currently we don't do anything with this
95*cf84ac9aSAndroid Build Coastguard Worker	next;
96*cf84ac9aSAndroid Build Coastguard Worker    }
97*cf84ac9aSAndroid Build Coastguard Worker
98*cf84ac9aSAndroid Build Coastguard Worker    ($call, $args, $result) = /(\S+)\((.*)\)\s+= (.*)$/;
99*cf84ac9aSAndroid Build Coastguard Worker    if ($result =~ /^(.*) <([0-9.]*)>$/) {
100*cf84ac9aSAndroid Build Coastguard Worker	($result, $time_spent) = ($1, $2);
101*cf84ac9aSAndroid Build Coastguard Worker    }
102*cf84ac9aSAndroid Build Coastguard Worker    unless (defined $result) {
103*cf84ac9aSAndroid Build Coastguard Worker	print STDERR "$0: $ARGV: $.: cannot parse line.\n";
104*cf84ac9aSAndroid Build Coastguard Worker	next;
105*cf84ac9aSAndroid Build Coastguard Worker    }
106*cf84ac9aSAndroid Build Coastguard Worker
107*cf84ac9aSAndroid Build Coastguard Worker    handle_trace($pid, $call, $args, $result, $time);
108*cf84ac9aSAndroid Build Coastguard Worker}
109*cf84ac9aSAndroid Build Coastguard Worker
110*cf84ac9aSAndroid Build Coastguard Workerdisplay_trace();
111*cf84ac9aSAndroid Build Coastguard Worker
112*cf84ac9aSAndroid Build Coastguard Workerexit 0;
113*cf84ac9aSAndroid Build Coastguard Worker
114*cf84ac9aSAndroid Build Coastguard Workersub parse_str {
115*cf84ac9aSAndroid Build Coastguard Worker    my ($in) = @_;
116*cf84ac9aSAndroid Build Coastguard Worker    my $result = "";
117*cf84ac9aSAndroid Build Coastguard Worker
118*cf84ac9aSAndroid Build Coastguard Worker    while (1) {
119*cf84ac9aSAndroid Build Coastguard Worker	if ($in =~ s/^\\(.)//) {
120*cf84ac9aSAndroid Build Coastguard Worker	    $result .= $1;
121*cf84ac9aSAndroid Build Coastguard Worker	} elsif ($in =~ s/^\"//) {
122*cf84ac9aSAndroid Build Coastguard Worker	    if ($in =~ s/^\.\.\.//) {
123*cf84ac9aSAndroid Build Coastguard Worker		return ("$result...", $in);
124*cf84ac9aSAndroid Build Coastguard Worker	    }
125*cf84ac9aSAndroid Build Coastguard Worker	    return ($result, $in);
126*cf84ac9aSAndroid Build Coastguard Worker	} elsif ($in =~ s/([^\\\"]*)//) {
127*cf84ac9aSAndroid Build Coastguard Worker	    $result .= $1;
128*cf84ac9aSAndroid Build Coastguard Worker	} else {
129*cf84ac9aSAndroid Build Coastguard Worker	    return (undef, $in);
130*cf84ac9aSAndroid Build Coastguard Worker	}
131*cf84ac9aSAndroid Build Coastguard Worker    }
132*cf84ac9aSAndroid Build Coastguard Worker}
133*cf84ac9aSAndroid Build Coastguard Worker
134*cf84ac9aSAndroid Build Coastguard Workersub parse_one {
135*cf84ac9aSAndroid Build Coastguard Worker    my ($in) = @_;
136*cf84ac9aSAndroid Build Coastguard Worker
137*cf84ac9aSAndroid Build Coastguard Worker    if ($in =~ s/^\"//) {
138*cf84ac9aSAndroid Build Coastguard Worker	my $tmp;
139*cf84ac9aSAndroid Build Coastguard Worker	($tmp, $in) = parse_str($in);
140*cf84ac9aSAndroid Build Coastguard Worker	if (not defined $tmp) {
141*cf84ac9aSAndroid Build Coastguard Worker	    print STDERR "$0: $ARGV: $.: cannot parse string.\n";
142*cf84ac9aSAndroid Build Coastguard Worker	    return (undef, $in);
143*cf84ac9aSAndroid Build Coastguard Worker	}
144*cf84ac9aSAndroid Build Coastguard Worker	return ($tmp, $in);
145*cf84ac9aSAndroid Build Coastguard Worker    } elsif ($in =~ s/^0x([[:xdigit:]]+)//) {
146*cf84ac9aSAndroid Build Coastguard Worker	return (hex $1, $in);
147*cf84ac9aSAndroid Build Coastguard Worker    } elsif ($in =~ s/^(\d+)//) {
148*cf84ac9aSAndroid Build Coastguard Worker	return (int $1, $in);
149*cf84ac9aSAndroid Build Coastguard Worker    } else {
150*cf84ac9aSAndroid Build Coastguard Worker	print STDERR "$0: $ARGV: $.: unrecognized element.\n";
151*cf84ac9aSAndroid Build Coastguard Worker	return (undef, $in);
152*cf84ac9aSAndroid Build Coastguard Worker    }
153*cf84ac9aSAndroid Build Coastguard Worker}
154*cf84ac9aSAndroid Build Coastguard Worker
155*cf84ac9aSAndroid Build Coastguard Workersub parseargs {
156*cf84ac9aSAndroid Build Coastguard Worker    my ($in) = @_;
157*cf84ac9aSAndroid Build Coastguard Worker    my @args = ();
158*cf84ac9aSAndroid Build Coastguard Worker    my $tmp;
159*cf84ac9aSAndroid Build Coastguard Worker
160*cf84ac9aSAndroid Build Coastguard Worker    while (length $in) {
161*cf84ac9aSAndroid Build Coastguard Worker	if ($in =~ s/^\[//) {
162*cf84ac9aSAndroid Build Coastguard Worker	    my @subarr = ();
163*cf84ac9aSAndroid Build Coastguard Worker	    if ($in =~ s,^/\* (\d+) vars \*/\],,) {
164*cf84ac9aSAndroid Build Coastguard Worker		push @args, $1;
165*cf84ac9aSAndroid Build Coastguard Worker	    } else {
166*cf84ac9aSAndroid Build Coastguard Worker		while ($in !~ s/^\]//) {
167*cf84ac9aSAndroid Build Coastguard Worker		    ($tmp, $in) = parse_one($in);
168*cf84ac9aSAndroid Build Coastguard Worker		    defined $tmp or return undef;
169*cf84ac9aSAndroid Build Coastguard Worker		    push @subarr, $tmp;
170*cf84ac9aSAndroid Build Coastguard Worker		    unless ($in =~ /^\]/ or $in =~ s/^, //) {
171*cf84ac9aSAndroid Build Coastguard Worker			print STDERR "$0: $ARGV: $.: missing comma in array.\n";
172*cf84ac9aSAndroid Build Coastguard Worker			return undef;
173*cf84ac9aSAndroid Build Coastguard Worker		    }
174*cf84ac9aSAndroid Build Coastguard Worker		    if ($in =~ s/^\.\.\.//) {
175*cf84ac9aSAndroid Build Coastguard Worker			push @subarr, "...";
176*cf84ac9aSAndroid Build Coastguard Worker		    }
177*cf84ac9aSAndroid Build Coastguard Worker		}
178*cf84ac9aSAndroid Build Coastguard Worker		push @args, \@subarr;
179*cf84ac9aSAndroid Build Coastguard Worker	    }
180*cf84ac9aSAndroid Build Coastguard Worker	} elsif ($in =~ s/^\{//) {
181*cf84ac9aSAndroid Build Coastguard Worker	    my %subhash = ();
182*cf84ac9aSAndroid Build Coastguard Worker	    while ($in !~ s/^\}//) {
183*cf84ac9aSAndroid Build Coastguard Worker		my $key;
184*cf84ac9aSAndroid Build Coastguard Worker		unless ($in =~ s/^(\w+)=//) {
185*cf84ac9aSAndroid Build Coastguard Worker		    print STDERR "$0: $ARGV: $.: struct field expected.\n";
186*cf84ac9aSAndroid Build Coastguard Worker		    return undef;
187*cf84ac9aSAndroid Build Coastguard Worker		}
188*cf84ac9aSAndroid Build Coastguard Worker		$key = $1;
189*cf84ac9aSAndroid Build Coastguard Worker		($tmp, $in) = parse_one($in);
190*cf84ac9aSAndroid Build Coastguard Worker		defined $tmp or return undef;
191*cf84ac9aSAndroid Build Coastguard Worker		$subhash{$key} = $tmp;
192*cf84ac9aSAndroid Build Coastguard Worker		unless ($in =~ s/, //) {
193*cf84ac9aSAndroid Build Coastguard Worker		    print STDERR "$0: $ARGV: $.: missing comma in struct.\n";
194*cf84ac9aSAndroid Build Coastguard Worker		    return undef;
195*cf84ac9aSAndroid Build Coastguard Worker		}
196*cf84ac9aSAndroid Build Coastguard Worker	    }
197*cf84ac9aSAndroid Build Coastguard Worker	    push @args, \%subhash;
198*cf84ac9aSAndroid Build Coastguard Worker	} else {
199*cf84ac9aSAndroid Build Coastguard Worker	    ($tmp, $in) = parse_one($in);
200*cf84ac9aSAndroid Build Coastguard Worker	    defined $tmp or return undef;
201*cf84ac9aSAndroid Build Coastguard Worker	    push @args, $tmp;
202*cf84ac9aSAndroid Build Coastguard Worker	}
203*cf84ac9aSAndroid Build Coastguard Worker	unless (length($in) == 0 or $in =~ s/^, //) {
204*cf84ac9aSAndroid Build Coastguard Worker	    print STDERR "$0: $ARGV: $.: missing comma.\n";
205*cf84ac9aSAndroid Build Coastguard Worker	    return undef;
206*cf84ac9aSAndroid Build Coastguard Worker	}
207*cf84ac9aSAndroid Build Coastguard Worker    }
208*cf84ac9aSAndroid Build Coastguard Worker    return @args;
209*cf84ac9aSAndroid Build Coastguard Worker}
210*cf84ac9aSAndroid Build Coastguard Worker
211*cf84ac9aSAndroid Build Coastguard Worker
212*cf84ac9aSAndroid Build Coastguard Workermy $depth = "";
213*cf84ac9aSAndroid Build Coastguard Worker
214*cf84ac9aSAndroid Build Coastguard Worker# process info, indexed by pid.
215*cf84ac9aSAndroid Build Coastguard Worker# fields:
216*cf84ac9aSAndroid Build Coastguard Worker#    parent         pid number
217*cf84ac9aSAndroid Build Coastguard Worker#    seq            clones, forks and execs for this pid, in sequence  (array)
218*cf84ac9aSAndroid Build Coastguard Worker
219*cf84ac9aSAndroid Build Coastguard Worker#  filename and argv (from latest exec)
220*cf84ac9aSAndroid Build Coastguard Worker#  basename (derived from filename)
221*cf84ac9aSAndroid Build Coastguard Worker# argv[0] is modified to add the basename if it differs from the 0th argument.
222*cf84ac9aSAndroid Build Coastguard Worker
223*cf84ac9aSAndroid Build Coastguard Workermy %pr;
224*cf84ac9aSAndroid Build Coastguard Worker
225*cf84ac9aSAndroid Build Coastguard Workersub handle_trace {
226*cf84ac9aSAndroid Build Coastguard Worker    my ($pid, $call, $args, $result, $time) = @_;
227*cf84ac9aSAndroid Build Coastguard Worker    my $pid_fqname = $pid . "-" . $time;
228*cf84ac9aSAndroid Build Coastguard Worker
229*cf84ac9aSAndroid Build Coastguard Worker    if (defined $time and not defined $running_fqname{$pid}) {
230*cf84ac9aSAndroid Build Coastguard Worker	$pr{$pid_fqname}{start} = $time;
231*cf84ac9aSAndroid Build Coastguard Worker	$running_fqname{$pid} = $pid_fqname;
232*cf84ac9aSAndroid Build Coastguard Worker    }
233*cf84ac9aSAndroid Build Coastguard Worker
234*cf84ac9aSAndroid Build Coastguard Worker    $pid_fqname = $running_fqname{$pid};
235*cf84ac9aSAndroid Build Coastguard Worker
236*cf84ac9aSAndroid Build Coastguard Worker    if ($call eq 'execve') {
237*cf84ac9aSAndroid Build Coastguard Worker	return if $result ne '0';
238*cf84ac9aSAndroid Build Coastguard Worker
239*cf84ac9aSAndroid Build Coastguard Worker	my ($filename, $argv) = parseargs($args);
240*cf84ac9aSAndroid Build Coastguard Worker	my ($basename) = $filename =~ m/([^\/]*)$/;
241*cf84ac9aSAndroid Build Coastguard Worker	if ($basename ne $$argv[0]) {
242*cf84ac9aSAndroid Build Coastguard Worker	    $$argv[0] = "$basename($$argv[0])";
243*cf84ac9aSAndroid Build Coastguard Worker	}
244*cf84ac9aSAndroid Build Coastguard Worker	my $seq = $pr{$pid_fqname}{seq};
245*cf84ac9aSAndroid Build Coastguard Worker	$seq = [] if not defined $seq;
246*cf84ac9aSAndroid Build Coastguard Worker
247*cf84ac9aSAndroid Build Coastguard Worker	push @$seq, ['EXEC', $filename, $argv];
248*cf84ac9aSAndroid Build Coastguard Worker
249*cf84ac9aSAndroid Build Coastguard Worker	$pr{$pid_fqname}{seq} = $seq;
250*cf84ac9aSAndroid Build Coastguard Worker    } elsif ($call eq 'fork' || $call eq 'clone' || $call eq 'vfork') {
251*cf84ac9aSAndroid Build Coastguard Worker	return if $result == 0;
252*cf84ac9aSAndroid Build Coastguard Worker
253*cf84ac9aSAndroid Build Coastguard Worker	my $seq = $pr{$pid_fqname}{seq};
254*cf84ac9aSAndroid Build Coastguard Worker	my $result_fqname= $result . "-" . $time;
255*cf84ac9aSAndroid Build Coastguard Worker	$seq = [] if not defined $seq;
256*cf84ac9aSAndroid Build Coastguard Worker	push @$seq, ['FORK', $result_fqname];
257*cf84ac9aSAndroid Build Coastguard Worker	$pr{$pid_fqname}{seq} = $seq;
258*cf84ac9aSAndroid Build Coastguard Worker	$pr{$result_fqname}{start} = $time;
259*cf84ac9aSAndroid Build Coastguard Worker	$pr{$result_fqname}{parent} = $pid_fqname;
260*cf84ac9aSAndroid Build Coastguard Worker	$pr{$result_fqname}{seq} = [];
261*cf84ac9aSAndroid Build Coastguard Worker	$running_fqname{$result} = $result_fqname;
262*cf84ac9aSAndroid Build Coastguard Worker    } elsif ($call eq '_exit' || $call eq 'exit_group') {
263*cf84ac9aSAndroid Build Coastguard Worker	$pr{$running_fqname{$pid}}{end} = $time if defined $time and not defined $pr{$running_fqname{$pid}}{end};
264*cf84ac9aSAndroid Build Coastguard Worker	delete $running_fqname{$pid};
265*cf84ac9aSAndroid Build Coastguard Worker    }
266*cf84ac9aSAndroid Build Coastguard Worker}
267*cf84ac9aSAndroid Build Coastguard Worker
268*cf84ac9aSAndroid Build Coastguard Workersub handle_killed {
269*cf84ac9aSAndroid Build Coastguard Worker    my ($pid, $time) = @_;
270*cf84ac9aSAndroid Build Coastguard Worker    $pr{$pid}{end} = $time if defined $time and not defined $pr{$pid}{end};
271*cf84ac9aSAndroid Build Coastguard Worker}
272*cf84ac9aSAndroid Build Coastguard Worker
273*cf84ac9aSAndroid Build Coastguard Workersub straight_seq {
274*cf84ac9aSAndroid Build Coastguard Worker    my ($pid) = @_;
275*cf84ac9aSAndroid Build Coastguard Worker    my $seq = $pr{$pid}{seq};
276*cf84ac9aSAndroid Build Coastguard Worker
277*cf84ac9aSAndroid Build Coastguard Worker    for my $elem (@$seq) {
278*cf84ac9aSAndroid Build Coastguard Worker	if ($$elem[0] eq 'EXEC') {
279*cf84ac9aSAndroid Build Coastguard Worker	    my $argv = $$elem[2];
280*cf84ac9aSAndroid Build Coastguard Worker	    print "$$elem[0] $$elem[1] @$argv\n";
281*cf84ac9aSAndroid Build Coastguard Worker	} elsif ($$elem[0] eq 'FORK') {
282*cf84ac9aSAndroid Build Coastguard Worker	    print "$$elem[0] $$elem[1]\n";
283*cf84ac9aSAndroid Build Coastguard Worker	} else {
284*cf84ac9aSAndroid Build Coastguard Worker	    print "$$elem[0]\n";
285*cf84ac9aSAndroid Build Coastguard Worker	}
286*cf84ac9aSAndroid Build Coastguard Worker    }
287*cf84ac9aSAndroid Build Coastguard Worker}
288*cf84ac9aSAndroid Build Coastguard Worker
289*cf84ac9aSAndroid Build Coastguard Workersub first_exec {
290*cf84ac9aSAndroid Build Coastguard Worker    my ($pid) = @_;
291*cf84ac9aSAndroid Build Coastguard Worker    my $seq = $pr{$pid}{seq};
292*cf84ac9aSAndroid Build Coastguard Worker
293*cf84ac9aSAndroid Build Coastguard Worker    for my $elem (@$seq) {
294*cf84ac9aSAndroid Build Coastguard Worker	if ($$elem[0] eq 'EXEC') {
295*cf84ac9aSAndroid Build Coastguard Worker	    return $elem;
296*cf84ac9aSAndroid Build Coastguard Worker	}
297*cf84ac9aSAndroid Build Coastguard Worker    }
298*cf84ac9aSAndroid Build Coastguard Worker    return undef;
299*cf84ac9aSAndroid Build Coastguard Worker}
300*cf84ac9aSAndroid Build Coastguard Worker
301*cf84ac9aSAndroid Build Coastguard Workersub display_pid_trace {
302*cf84ac9aSAndroid Build Coastguard Worker    my ($pid, $lead) = @_;
303*cf84ac9aSAndroid Build Coastguard Worker    my $i = 0;
304*cf84ac9aSAndroid Build Coastguard Worker    my @seq = @{$pr{$pid}{seq}};
305*cf84ac9aSAndroid Build Coastguard Worker    my $elapsed;
306*cf84ac9aSAndroid Build Coastguard Worker
307*cf84ac9aSAndroid Build Coastguard Worker    if (not defined first_exec($pid)) {
308*cf84ac9aSAndroid Build Coastguard Worker	unshift @seq, ['EXEC', '', ['(anon)'] ];
309*cf84ac9aSAndroid Build Coastguard Worker    }
310*cf84ac9aSAndroid Build Coastguard Worker
311*cf84ac9aSAndroid Build Coastguard Worker    if (defined $pr{$pid}{start} and defined $pr{$pid}{end}) {
312*cf84ac9aSAndroid Build Coastguard Worker	$elapsed = $pr{$pid}{end} - $pr{$pid}{start};
313*cf84ac9aSAndroid Build Coastguard Worker	$elapsed /= $scale_factor;
314*cf84ac9aSAndroid Build Coastguard Worker	if ($floatform) {
315*cf84ac9aSAndroid Build Coastguard Worker	    $elapsed = sprintf("%0.02f", $elapsed);
316*cf84ac9aSAndroid Build Coastguard Worker	} else {
317*cf84ac9aSAndroid Build Coastguard Worker	    $elapsed = int $elapsed;
318*cf84ac9aSAndroid Build Coastguard Worker	}
319*cf84ac9aSAndroid Build Coastguard Worker    }
320*cf84ac9aSAndroid Build Coastguard Worker
321*cf84ac9aSAndroid Build Coastguard Worker    for my $elem (@seq) {
322*cf84ac9aSAndroid Build Coastguard Worker	$i++;
323*cf84ac9aSAndroid Build Coastguard Worker	if ($$elem[0] eq 'EXEC') {
324*cf84ac9aSAndroid Build Coastguard Worker	    my $argv = $$elem[2];
325*cf84ac9aSAndroid Build Coastguard Worker	    if (defined $elapsed) {
326*cf84ac9aSAndroid Build Coastguard Worker		print "$lead [$elapsed] $pid @$argv\n";
327*cf84ac9aSAndroid Build Coastguard Worker		undef $elapsed;
328*cf84ac9aSAndroid Build Coastguard Worker	    } else {
329*cf84ac9aSAndroid Build Coastguard Worker		print "$lead $pid @$argv\n";
330*cf84ac9aSAndroid Build Coastguard Worker	    }
331*cf84ac9aSAndroid Build Coastguard Worker	} elsif ($$elem[0] eq 'FORK') {
332*cf84ac9aSAndroid Build Coastguard Worker	    if ($i == 1) {
333*cf84ac9aSAndroid Build Coastguard Worker		if ($lead =~ /-$/) {
334*cf84ac9aSAndroid Build Coastguard Worker		    display_pid_trace($$elem[1], "$lead--+--");
335*cf84ac9aSAndroid Build Coastguard Worker		} else {
336*cf84ac9aSAndroid Build Coastguard Worker		    display_pid_trace($$elem[1], "$lead  +--");
337*cf84ac9aSAndroid Build Coastguard Worker		}
338*cf84ac9aSAndroid Build Coastguard Worker	    } elsif ($i == @seq) {
339*cf84ac9aSAndroid Build Coastguard Worker		display_pid_trace($$elem[1], "$lead  `--");
340*cf84ac9aSAndroid Build Coastguard Worker	    } else {
341*cf84ac9aSAndroid Build Coastguard Worker		display_pid_trace($$elem[1], "$lead  +--");
342*cf84ac9aSAndroid Build Coastguard Worker	    }
343*cf84ac9aSAndroid Build Coastguard Worker	}
344*cf84ac9aSAndroid Build Coastguard Worker	if ($i == 1) {
345*cf84ac9aSAndroid Build Coastguard Worker	    $lead =~ s/\`--/   /g;
346*cf84ac9aSAndroid Build Coastguard Worker	    $lead =~ s/-/ /g;
347*cf84ac9aSAndroid Build Coastguard Worker	    $lead =~ s/\+/|/g;
348*cf84ac9aSAndroid Build Coastguard Worker	}
349*cf84ac9aSAndroid Build Coastguard Worker    }
350*cf84ac9aSAndroid Build Coastguard Worker}
351*cf84ac9aSAndroid Build Coastguard Worker
352*cf84ac9aSAndroid Build Coastguard Workersub display_trace {
353*cf84ac9aSAndroid Build Coastguard Worker    my ($startpid) = @_;
354*cf84ac9aSAndroid Build Coastguard Worker
355*cf84ac9aSAndroid Build Coastguard Worker    $startpid = (keys %pr)[0];
356*cf84ac9aSAndroid Build Coastguard Worker    while ($pr{$startpid}{parent}) {
357*cf84ac9aSAndroid Build Coastguard Worker	$startpid = $pr{$startpid}{parent};
358*cf84ac9aSAndroid Build Coastguard Worker    }
359*cf84ac9aSAndroid Build Coastguard Worker
360*cf84ac9aSAndroid Build Coastguard Worker    display_pid_trace($startpid, "");
361*cf84ac9aSAndroid Build Coastguard Worker}
362