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