261 lines
5.8 KiB
Bash
261 lines
5.8 KiB
Bash
|
#!/bin/sh
|
||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||
|
|
||
|
usage() {
|
||
|
echo "Dump boot-time tracing bootconfig from ftrace"
|
||
|
echo "Usage: $0 [--debug] [ > BOOTCONFIG-FILE]"
|
||
|
exit 1
|
||
|
}
|
||
|
|
||
|
DEBUG=
|
||
|
while [ x"$1" != x ]; do
|
||
|
case "$1" in
|
||
|
"--debug")
|
||
|
DEBUG=$1;;
|
||
|
-*)
|
||
|
usage
|
||
|
;;
|
||
|
esac
|
||
|
shift 1
|
||
|
done
|
||
|
|
||
|
if [ x"$DEBUG" != x ]; then
|
||
|
set -x
|
||
|
fi
|
||
|
|
||
|
TRACEFS=`grep -m 1 -w tracefs /proc/mounts | cut -f 2 -d " "`
|
||
|
if [ -z "$TRACEFS" ]; then
|
||
|
if ! grep -wq debugfs /proc/mounts; then
|
||
|
echo "Error: No tracefs/debugfs was mounted."
|
||
|
exit 1
|
||
|
fi
|
||
|
TRACEFS=`grep -m 1 -w debugfs /proc/mounts | cut -f 2 -d " "`/tracing
|
||
|
if [ ! -d $TRACEFS ]; then
|
||
|
echo "Error: ftrace is not enabled on this kernel." 1>&2
|
||
|
exit 1
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
######## main #########
|
||
|
|
||
|
set -e
|
||
|
|
||
|
emit_kv() { # key =|+= value
|
||
|
echo "$@"
|
||
|
}
|
||
|
|
||
|
global_options() {
|
||
|
val=`cat $TRACEFS/max_graph_depth`
|
||
|
[ $val != 0 ] && emit_kv kernel.fgraph_max_depth = $val
|
||
|
if grep -qv "^#" $TRACEFS/set_graph_function $TRACEFS/set_graph_notrace ; then
|
||
|
cat 1>&2 << EOF
|
||
|
# WARN: kernel.fgraph_filters and kernel.fgraph_notrace are not supported, since the wild card expression was expanded and lost from memory.
|
||
|
EOF
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
kprobe_event_options() {
|
||
|
cat $TRACEFS/kprobe_events | while read p args; do
|
||
|
case $p in
|
||
|
r*)
|
||
|
cat 1>&2 << EOF
|
||
|
# WARN: A return probe found but it is not supported by bootconfig. Skip it.
|
||
|
EOF
|
||
|
continue;;
|
||
|
esac
|
||
|
p=${p#*:}
|
||
|
event=${p#*/}
|
||
|
group=${p%/*}
|
||
|
if [ $group != "kprobes" ]; then
|
||
|
cat 1>&2 << EOF
|
||
|
# WARN: kprobes group name $group is changed to "kprobes" for bootconfig.
|
||
|
EOF
|
||
|
fi
|
||
|
emit_kv $PREFIX.event.kprobes.$event.probes += $args
|
||
|
done
|
||
|
}
|
||
|
|
||
|
synth_event_options() {
|
||
|
cat $TRACEFS/synthetic_events | while read event fields; do
|
||
|
emit_kv $PREFIX.event.synthetic.$event.fields = `echo $fields | sed "s/;/,/g"`
|
||
|
done
|
||
|
}
|
||
|
|
||
|
# Variables resolver
|
||
|
DEFINED_VARS=
|
||
|
UNRESOLVED_EVENTS=
|
||
|
|
||
|
defined_vars() { # event-dir
|
||
|
grep "^hist" $1/trigger | grep -o ':[a-zA-Z0-9]*='
|
||
|
}
|
||
|
referred_vars() {
|
||
|
grep "^hist" $1/trigger | grep -o '$[a-zA-Z0-9]*'
|
||
|
}
|
||
|
|
||
|
event_is_enabled() { # enable-file
|
||
|
test -f $1 && grep -q "1" $1
|
||
|
}
|
||
|
|
||
|
per_event_options() { # event-dir
|
||
|
evdir=$1
|
||
|
# Check the special event which has no filter and no trigger
|
||
|
[ ! -f $evdir/filter ] && return
|
||
|
|
||
|
if grep -q "^hist:" $evdir/trigger; then
|
||
|
# hist action can refer the undefined variables
|
||
|
__vars=`defined_vars $evdir`
|
||
|
for v in `referred_vars $evdir`; do
|
||
|
if echo $DEFINED_VARS $__vars | grep -vqw ${v#$}; then
|
||
|
# $v is not defined yet, defer it
|
||
|
UNRESOLVED_EVENTS="$UNRESOLVED_EVENTS $evdir"
|
||
|
return;
|
||
|
fi
|
||
|
done
|
||
|
DEFINED_VARS="$DEFINED_VARS "`defined_vars $evdir`
|
||
|
fi
|
||
|
grep -v "^#" $evdir/trigger | while read action active; do
|
||
|
emit_kv $PREFIX.event.$group.$event.actions += \'$action\'
|
||
|
done
|
||
|
|
||
|
if [ $GROUP_ENABLED -eq 0 ] && event_is_enabled $evdir/enable; then
|
||
|
emit_kv $PREFIX.event.$group.$event.enable
|
||
|
fi
|
||
|
val=`cat $evdir/filter`
|
||
|
if [ "$val" != "none" ]; then
|
||
|
emit_kv $PREFIX.event.$group.$event.filter = "$val"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
retry_unresolved() {
|
||
|
unresolved=$UNRESOLVED_EVENTS
|
||
|
UNRESOLVED_EVENTS=
|
||
|
for evdir in $unresolved; do
|
||
|
event=${evdir##*/}
|
||
|
group=${evdir%/*}; group=${group##*/}
|
||
|
per_event_options $evdir
|
||
|
done
|
||
|
}
|
||
|
|
||
|
event_options() {
|
||
|
# PREFIX and INSTANCE must be set
|
||
|
if [ $PREFIX = "ftrace" ]; then
|
||
|
# define the dynamic events
|
||
|
kprobe_event_options
|
||
|
synth_event_options
|
||
|
fi
|
||
|
ALL_ENABLED=0
|
||
|
if event_is_enabled $INSTANCE/events/enable; then
|
||
|
emit_kv $PREFIX.event.enable
|
||
|
ALL_ENABLED=1
|
||
|
fi
|
||
|
for group in `ls $INSTANCE/events/` ; do
|
||
|
[ ! -d $INSTANCE/events/$group ] && continue
|
||
|
GROUP_ENABLED=$ALL_ENABLED
|
||
|
if [ $ALL_ENABLED -eq 0 ] && \
|
||
|
event_is_enabled $INSTANCE/events/$group/enable ;then
|
||
|
emit_kv $PREFIX.event.$group.enable
|
||
|
GROUP_ENABLED=1
|
||
|
fi
|
||
|
for event in `ls $INSTANCE/events/$group/` ;do
|
||
|
[ ! -d $INSTANCE/events/$group/$event ] && continue
|
||
|
per_event_options $INSTANCE/events/$group/$event
|
||
|
done
|
||
|
done
|
||
|
retry=0
|
||
|
while [ $retry -lt 3 ]; do
|
||
|
retry_unresolved
|
||
|
retry=$((retry + 1))
|
||
|
done
|
||
|
if [ "$UNRESOLVED_EVENTS" ]; then
|
||
|
cat 1>&2 << EOF
|
||
|
! ERROR: hist triggers in $UNRESOLVED_EVENTS use some undefined variables.
|
||
|
EOF
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
is_default_trace_option() { # option
|
||
|
grep -qw $1 << EOF
|
||
|
print-parent
|
||
|
nosym-offset
|
||
|
nosym-addr
|
||
|
noverbose
|
||
|
noraw
|
||
|
nohex
|
||
|
nobin
|
||
|
noblock
|
||
|
trace_printk
|
||
|
annotate
|
||
|
nouserstacktrace
|
||
|
nosym-userobj
|
||
|
noprintk-msg-only
|
||
|
context-info
|
||
|
nolatency-format
|
||
|
record-cmd
|
||
|
norecord-tgid
|
||
|
overwrite
|
||
|
nodisable_on_free
|
||
|
irq-info
|
||
|
markers
|
||
|
noevent-fork
|
||
|
nopause-on-trace
|
||
|
function-trace
|
||
|
nofunction-fork
|
||
|
nodisplay-graph
|
||
|
nostacktrace
|
||
|
notest_nop_accept
|
||
|
notest_nop_refuse
|
||
|
EOF
|
||
|
}
|
||
|
|
||
|
instance_options() { # [instance-name]
|
||
|
if [ $# -eq 0 ]; then
|
||
|
PREFIX="ftrace"
|
||
|
INSTANCE=$TRACEFS
|
||
|
else
|
||
|
PREFIX="ftrace.instance.$1"
|
||
|
INSTANCE=$TRACEFS/instances/$1
|
||
|
fi
|
||
|
val=
|
||
|
for i in `cat $INSTANCE/trace_options`; do
|
||
|
is_default_trace_option $i && continue
|
||
|
val="$val, $i"
|
||
|
done
|
||
|
[ "$val" ] && emit_kv $PREFIX.options = "${val#,}"
|
||
|
val="local"
|
||
|
for i in `cat $INSTANCE/trace_clock` ; do
|
||
|
[ "${i#*]}" ] && continue
|
||
|
i=${i%]}; val=${i#[}
|
||
|
done
|
||
|
[ $val != "local" ] && emit_kv $PREFIX.trace_clock = $val
|
||
|
val=`cat $INSTANCE/buffer_size_kb`
|
||
|
if echo $val | grep -vq "expanded" ; then
|
||
|
emit_kv $PREFIX.buffer_size = $val"KB"
|
||
|
fi
|
||
|
if grep -q "is allocated" $INSTANCE/snapshot ; then
|
||
|
emit_kv $PREFIX.alloc_snapshot
|
||
|
fi
|
||
|
val=`cat $INSTANCE/tracing_cpumask`
|
||
|
if [ `echo $val | sed -e s/f//g`x != x ]; then
|
||
|
emit_kv $PREFIX.cpumask = $val
|
||
|
fi
|
||
|
val=`cat $INSTANCE/tracing_on`
|
||
|
if [ "$val" = "0" ]; then
|
||
|
emit_kv $PREFIX.tracing_on = 0
|
||
|
fi
|
||
|
|
||
|
val=`cat $INSTANCE/current_tracer`
|
||
|
[ $val != nop ] && emit_kv $PREFIX.tracer = $val
|
||
|
if grep -qv "^#" $INSTANCE/set_ftrace_filter $INSTANCE/set_ftrace_notrace; then
|
||
|
cat 1>&2 << EOF
|
||
|
# WARN: kernel.ftrace.filters and kernel.ftrace.notrace are not supported, since the wild card expression was expanded and lost from memory.
|
||
|
EOF
|
||
|
fi
|
||
|
event_options
|
||
|
}
|
||
|
|
||
|
global_options
|
||
|
instance_options
|
||
|
for i in `ls $TRACEFS/instances` ; do
|
||
|
instance_options $i
|
||
|
done
|