| #!/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 |