1235368Sgnn#!/usr/sbin/dtrace -Zs
2235368Sgnn/*
3235368Sgnn * sh_syscolors.d - trace Bourne shell flow plus syscalls, in color.
4235368Sgnn *                  Written for the sh DTrace provider.
5235368Sgnn *
6235368Sgnn * $Id: sh_syscolors.d 27 2007-09-13 09:26:01Z brendan $
7235368Sgnn *
8235368Sgnn * USAGE: sh_syscolors.d { -p PID | -c cmd }	# hit Ctrl-C to end
9235368Sgnn *
10235368Sgnn * This watches shell function entries and returns, and indents child
11235368Sgnn * function calls. Shell builtins, commands and lines are also printed.
12235368Sgnn *
13235368Sgnn * FIELDS:
14235368Sgnn *		C		CPU-id
15235368Sgnn *		PID		Process ID
16235368Sgnn *		DELTA(us)	Elapsed time from previous line to this line
17235368Sgnn *		FILE		Filename of the shell script
18235368Sgnn *		LINE		Line number of filename
19235368Sgnn *		TYPE		Type of call (func/builtin/cmd/line/shell)
20235368Sgnn *		NAME		Shell function, builtin or command name
21235368Sgnn *
22235368Sgnn * The filename for syscalls may be printed as the shell name, if the
23235368Sgnn * script was invoked using the form "shell filename" rather than running
24235368Sgnn * the script with an interpreter line.
25235368Sgnn *
26235368Sgnn * WARNING: Watch the first column carefully, it prints the CPU-id. If it
27235368Sgnn * changes, then it is very likely that the output has been shuffled.
28235368Sgnn *
29235368Sgnn * COPYRIGHT: Copyright (c) 2007 Brendan Gregg.
30235368Sgnn *
31235368Sgnn * CDDL HEADER START
32235368Sgnn *
33235368Sgnn *  The contents of this file are subject to the terms of the
34235368Sgnn *  Common Development and Distribution License, Version 1.0 only
35235368Sgnn *  (the "License").  You may not use this file except in compliance
36235368Sgnn *  with the License.
37235368Sgnn *
38235368Sgnn *  You can obtain a copy of the license at Docs/cddl1.txt
39235368Sgnn *  or http://www.opensolaris.org/os/licensing.
40235368Sgnn *  See the License for the specific language governing permissions
41235368Sgnn *  and limitations under the License.
42235368Sgnn *
43235368Sgnn * CDDL HEADER END
44235368Sgnn *
45235368Sgnn * 09-Sep-2007	Brendan Gregg	Created this.
46235368Sgnn */
47235368Sgnn
48235368Sgnn#pragma D option quiet
49235368Sgnn#pragma D option switchrate=10
50235368Sgnn
51235368Sgnnself int depth;
52235368Sgnn
53235368Sgnndtrace:::BEGIN
54235368Sgnn{
55235368Sgnn        color_shell = "\033[2;35m";		/* violet, faint */
56235368Sgnn        color_line = "\033[1;35m";		/* violet, bold */
57235368Sgnn        color_syscall = "\033[2;32m";		/* green, faint */
58235368Sgnn        color_off = "\033[0m";			/* default */
59235368Sgnn
60235368Sgnn	printf("%s %6s %10s  %16s:%-4s %-8s -- %s\n", "C", "PID", "DELTA(us)",
61235368Sgnn	    "FILE", "LINE", "TYPE", "NAME");
62235368Sgnn}
63235368Sgnn
64235368Sgnnsh$target:::function-entry,
65235368Sgnnsh$target:::function-return,
66235368Sgnnsh$target:::builtin-entry,
67235368Sgnnsh$target:::command-entry,
68235368Sgnnsh$target:::line,
69235368Sgnnsyscall:::entry,
70235368Sgnnsyscall:::return
71235368Sgnn/self->last == 0 && pid == $target/
72235368Sgnn{
73235368Sgnn	self->last = timestamp;
74235368Sgnn}
75235368Sgnn
76235368Sgnnsh$target:::function-entry
77235368Sgnn{
78235368Sgnn	this->delta = (timestamp - self->last) / 1000;
79235368Sgnn	printf("%s%d %6d %10d  %16s:%-4d %-8s %*s-> %s%s\n", color_shell,
80235368Sgnn	    cpu, pid, this->delta, basename(copyinstr(arg0)), arg2, "func",
81235368Sgnn	    self->depth * 2, "", copyinstr(arg1), color_off);
82235368Sgnn	self->depth++;
83235368Sgnn	self->last = timestamp;
84235368Sgnn}
85235368Sgnn
86235368Sgnnsh$target:::function-return
87235368Sgnn{
88235368Sgnn	this->delta = (timestamp - self->last) / 1000;
89235368Sgnn	self->depth -= self->depth > 0 ? 1 : 0;
90235368Sgnn	printf("%s%d %6d %10d  %16s:-    %-8s %*s<- %s%s\n", color_shell,
91235368Sgnn	    cpu, pid, this->delta, basename(copyinstr(arg0)), "func",
92235368Sgnn	    self->depth * 2, "", copyinstr(arg1), color_off);
93235368Sgnn	self->last = timestamp;
94235368Sgnn}
95235368Sgnn
96235368Sgnnsh$target:::builtin-entry
97235368Sgnn{
98235368Sgnn	this->delta = (timestamp - self->last) / 1000;
99235368Sgnn	printf("%s%d %6d %10d  %16s:%-4d %-8s %*s-> %s%s\n", color_shell,
100235368Sgnn	    cpu, pid, this->delta, basename(copyinstr(arg0)), arg2, "builtin",
101235368Sgnn	    self->depth * 2, "", copyinstr(arg1), color_off);
102235368Sgnn	self->depth++;
103235368Sgnn	self->last = timestamp;
104235368Sgnn}
105235368Sgnn
106235368Sgnnsh$target:::builtin-return
107235368Sgnn{
108235368Sgnn	this->delta = (timestamp - self->last) / 1000;
109235368Sgnn	self->depth -= self->depth > 0 ? 1 : 0;
110235368Sgnn	printf("%s%d %6d %10d  %16s:%-4d %-8s %*s<- %s%s\n", color_shell,
111235368Sgnn	    cpu, pid, this->delta, basename(copyinstr(arg0)), arg2, "builtin",
112235368Sgnn	    self->depth * 2, "", copyinstr(arg1), color_off);
113235368Sgnn	self->last = timestamp;
114235368Sgnn}
115235368Sgnn
116235368Sgnnsh$target:::command-entry
117235368Sgnn{
118235368Sgnn	this->delta = (timestamp - self->last) / 1000;
119235368Sgnn	printf("%s%d %6d %10d  %16s:%-4d %-8s %*s-> %s%s\n", color_shell,
120235368Sgnn	    cpu, pid, this->delta, basename(copyinstr(arg0)), arg2, "cmd",
121235368Sgnn	    self->depth * 2, "", copyinstr(arg1), color_off);
122235368Sgnn	self->depth++;
123235368Sgnn	self->last = timestamp;
124235368Sgnn}
125235368Sgnn
126235368Sgnnsh$target:::command-return
127235368Sgnn{
128235368Sgnn	this->delta = (timestamp - self->last) / 1000;
129235368Sgnn	self->depth -= self->depth > 0 ? 1 : 0;
130235368Sgnn	printf("%s%d %6d %10d  %16s:%-4d %-8s %*s<- %s%s\n", color_shell,
131235368Sgnn	    cpu, pid, this->delta, basename(copyinstr(arg0)), arg2, "cmd",
132235368Sgnn	    self->depth * 2, "", copyinstr(arg1), color_off);
133235368Sgnn	self->last = timestamp;
134235368Sgnn}
135235368Sgnn
136235368Sgnnsh$target:::line
137235368Sgnn{
138235368Sgnn	this->delta = (timestamp - self->last) / 1000;
139235368Sgnn	printf("%s%d %6d %10d  %16s:%-4d %-8s %*s-- %s\n", color_line,
140235368Sgnn	    cpu, pid, this->delta, basename(copyinstr(arg0)), arg1, "line",
141235368Sgnn	    self->depth * 2, "", color_off);
142235368Sgnn	self->last = timestamp;
143235368Sgnn}
144235368Sgnn
145235368Sgnnsyscall:::entry
146235368Sgnn/pid == $target/
147235368Sgnn{
148235368Sgnn	this->delta = (timestamp - self->last) / 1000;
149235368Sgnn	printf("%s%d %6d %10d  %16s:-    %-8s %*s-> %s%s\n", color_syscall,
150235368Sgnn	    cpu, pid, this->delta, basename(execname), "syscall",
151235368Sgnn	    self->depth * 2, "", probefunc, color_off);
152235368Sgnn	self->last = timestamp;
153235368Sgnn}
154235368Sgnn
155235368Sgnnsyscall:::return
156235368Sgnn/pid == $target/
157235368Sgnn{
158235368Sgnn	this->delta = (timestamp - self->last) / 1000;
159235368Sgnn	printf("%s%d %6d %10d  %16s:-    %-8s %*s<- %s%s\n", color_syscall,
160235368Sgnn	    cpu, pid, this->delta, basename(execname), "syscall",
161235368Sgnn	    self->depth * 2, "", probefunc, color_off);
162235368Sgnn	self->last = timestamp;
163235368Sgnn}
164235368Sgnn
165235368Sgnnproc:::exit
166235368Sgnn/pid == $target/
167235368Sgnn{
168235368Sgnn	exit(0);
169235368Sgnn}
170