1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-only
3
4usage() {
5	echo "Dump boot-time tracing bootconfig from ftrace"
6	echo "Usage: $0 [--debug] [ > BOOTCONFIG-FILE]"
7	exit 1
8}
9
10DEBUG=
11while [ x"$1" != x ]; do
12	case "$1" in
13	"--debug")
14		DEBUG=$1;;
15	-*)
16		usage
17		;;
18	esac
19	shift 1
20done
21
22if [ x"$DEBUG" != x ]; then
23	set -x
24fi
25
26TRACEFS=`grep -m 1 -w tracefs /proc/mounts | cut -f 2 -d " "`
27if [ -z "$TRACEFS" ]; then
28	if ! grep -wq debugfs /proc/mounts; then
29		echo "Error: No tracefs/debugfs was mounted."
30		exit 1
31	fi
32	TRACEFS=`grep -m 1 -w debugfs /proc/mounts | cut -f 2 -d " "`/tracing
33	if [ ! -d $TRACEFS ]; then
34		echo "Error: ftrace is not enabled on this kernel." 1>&2
35		exit 1
36	fi
37fi
38
39######## main #########
40
41set -e
42
43emit_kv() { # key =|+= value
44	echo "$@"
45}
46
47global_options() {
48	val=`cat $TRACEFS/max_graph_depth`
49	[ $val != 0 ] && emit_kv kernel.fgraph_max_depth = $val
50	if grep -qv "^#" $TRACEFS/set_graph_function $TRACEFS/set_graph_notrace ; then
51		cat 1>&2 << EOF
52# WARN: kernel.fgraph_filters and kernel.fgraph_notrace are not supported, since the wild card expression was expanded and lost from memory.
53EOF
54	fi
55}
56
57kprobe_event_options() {
58	cat $TRACEFS/kprobe_events | while read p args; do
59		case $p in
60		r*)
61		cat 1>&2 << EOF
62# WARN: A return probe found but it is not supported by bootconfig. Skip it.
63EOF
64		continue;;
65		esac
66		p=${p#*:}
67		event=${p#*/}
68		group=${p%/*}
69		if [ $group != "kprobes" ]; then
70			cat 1>&2 << EOF
71# WARN: kprobes group name $group is changed to "kprobes" for bootconfig.
72EOF
73		fi
74		emit_kv $PREFIX.event.kprobes.$event.probes += $args
75	done
76}
77
78synth_event_options() {
79	cat $TRACEFS/synthetic_events | while read event fields; do
80		emit_kv $PREFIX.event.synthetic.$event.fields = `echo $fields | sed "s/;/,/g"`
81	done
82}
83
84# Variables resolver
85DEFINED_VARS=
86UNRESOLVED_EVENTS=
87
88defined_vars() { # event-dir
89	grep "^hist" $1/trigger | grep -o ':[a-zA-Z0-9]*='
90}
91referred_vars() {
92	grep "^hist" $1/trigger | grep -o '$[a-zA-Z0-9]*'
93}
94
95event_is_enabled() { # enable-file
96	test -f $1 & grep -q "1" $1
97}
98
99per_event_options() { # event-dir
100	evdir=$1
101	# Check the special event which has no filter and no trigger
102	[ ! -f $evdir/filter ] && return
103
104	if grep -q "^hist:" $evdir/trigger; then
105		# hist action can refer the undefined variables
106		__vars=`defined_vars $evdir`
107		for v in `referred_vars $evdir`; do
108			if echo $DEFINED_VARS $__vars | grep -vqw ${v#$}; then
109				# $v is not defined yet, defer it
110				UNRESOLVED_EVENTS="$UNRESOLVED_EVENTS $evdir"
111				return;
112			fi
113		done
114		DEFINED_VARS="$DEFINED_VARS "`defined_vars $evdir`
115	fi
116	grep -v "^#" $evdir/trigger | while read action active; do
117		emit_kv $PREFIX.event.$group.$event.actions += \'$action\'
118	done
119
120	if [ $GROUP_ENABLED -eq 0 ] && event_is_enabled $evdir/enable; then
121		emit_kv $PREFIX.event.$group.$event.enable
122	fi
123	val=`cat $evdir/filter`
124	if [ "$val" != "none" ]; then
125		emit_kv $PREFIX.event.$group.$event.filter = "$val"
126	fi
127}
128
129retry_unresolved() {
130	unresolved=$UNRESOLVED_EVENTS
131	UNRESOLVED_EVENTS=
132	for evdir in $unresolved; do
133		event=${evdir##*/}
134		group=${evdir%/*}; group=${group##*/}
135		per_event_options $evdir
136	done
137}
138
139event_options() {
140	# PREFIX and INSTANCE must be set
141	if [ $PREFIX = "ftrace" ]; then
142		# define the dynamic events
143		kprobe_event_options
144		synth_event_options
145	fi
146	ALL_ENABLED=0
147	if event_is_enabled $INSTANCE/events/enable; then
148		emit_kv $PREFIX.event.enable
149		ALL_ENABLED=1
150	fi
151	for group in `ls $INSTANCE/events/` ; do
152		[ ! -d $INSTANCE/events/$group ] && continue
153		GROUP_ENABLED=$ALL_ENABLED
154		if [ $ALL_ENABLED -eq 0 ] && \
155		   event_is_enabled $INSTANCE/events/$group/enable ;then
156			emit_kv $PREFIX.event.$group.enable
157			GROUP_ENABLED=1
158		fi
159		for event in `ls $INSTANCE/events/$group/` ;do
160			[ ! -d $INSTANCE/events/$group/$event ] && continue
161			per_event_options $INSTANCE/events/$group/$event
162		done
163	done
164	retry=0
165	while [ $retry -lt 3 ]; do
166		retry_unresolved
167		retry=$((retry + 1))
168	done
169	if [ "$UNRESOLVED_EVENTS" ]; then
170		cat 1>&2 << EOF
171! ERROR: hist triggers in $UNRESOLVED_EVENTS use some undefined variables.
172EOF
173	fi
174}
175
176is_default_trace_option() { # option
177grep -qw $1 << EOF
178print-parent
179nosym-offset
180nosym-addr
181noverbose
182noraw
183nohex
184nobin
185noblock
186trace_printk
187annotate
188nouserstacktrace
189nosym-userobj
190noprintk-msg-only
191context-info
192nolatency-format
193record-cmd
194norecord-tgid
195overwrite
196nodisable_on_free
197irq-info
198markers
199noevent-fork
200nopause-on-trace
201function-trace
202nofunction-fork
203nodisplay-graph
204nostacktrace
205notest_nop_accept
206notest_nop_refuse
207EOF
208}
209
210instance_options() { # [instance-name]
211	if [ $# -eq 0 ]; then
212		PREFIX="ftrace"
213		INSTANCE=$TRACEFS
214	else
215		PREFIX="ftrace.instance.$1"
216		INSTANCE=$TRACEFS/instances/$1
217	fi
218	val=
219	for i in `cat $INSTANCE/trace_options`; do
220		is_default_trace_option $i && continue
221		val="$val, $i"
222	done
223	[ "$val" ] && emit_kv $PREFIX.options = "${val#,}"
224	val="local"
225	for i in `cat $INSTANCE/trace_clock` ; do
226		[ "${i#*]}" ] && continue
227		i=${i%]}; val=${i#[}
228	done
229	[ $val != "local" ] && emit_kv $PREFIX.trace_clock = $val
230	val=`cat $INSTANCE/buffer_size_kb`
231	if echo $val | grep -vq "expanded" ; then
232		emit_kv $PREFIX.buffer_size = $val"KB"
233	fi
234	if grep -q "is allocated" $INSTANCE/snapshot ; then
235		emit_kv $PREFIX.alloc_snapshot
236	fi
237	val=`cat $INSTANCE/tracing_cpumask`
238	if [ `echo $val | sed -e s/f//g`x != x ]; then
239		emit_kv $PREFIX.cpumask = $val
240	fi
241	val=`cat $INSTANCE/tracing_on`
242	if [ "$val" = "0" ]; then
243		emit_kv $PREFIX.tracing_on = 0
244	fi
245
246	val=`cat $INSTANCE/current_tracer`
247	[ $val != nop ] && emit_kv $PREFIX.tracer = $val
248	if grep -qv "^#" $INSTANCE/set_ftrace_filter $INSTANCE/set_ftrace_notrace; then
249		cat 1>&2 << EOF
250# WARN: kernel.ftrace.filters and kernel.ftrace.notrace are not supported, since the wild card expression was expanded and lost from memory.
251EOF
252	fi
253	event_options
254}
255
256global_options
257instance_options
258for i in `ls $TRACEFS/instances` ; do
259	instance_options $i
260done
261