1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-or-later
3# Copyright (C) 2017 Red Hat, Inc.
4#
5# Test functionality of dynamic debug feature by enabling
6# and disabling traces with available flags. Check that these
7# settings don't cause issues by searching dmesg.
8#
9# This test handles changes of dynamic debug interface from
10# commits 5ca7d2a6 (dynamic_debug: describe_flags with
11# '=[pmflt_]*') and 8ba6ebf5 (Dynamic debug: Add more flags)
12
13TST_TESTFUNC=ddebug_test
14TST_NEEDS_CMDS="awk /bin/echo"
15TST_NEEDS_TMPDIR=1
16TST_NEEDS_ROOT=1
17TST_SETUP=setup
18TST_CLEANUP=cleanup
19
20. tst_test.sh
21
22
23DEBUGFS_WAS_MOUNTED=0
24DEBUGFS_PATH=""
25DEBUGFS_CONTROL=""
26DYNDEBUG_STATEMENTS="./debug_statements"
27EMPTY_FLAG="-"
28NEW_INTERFACE=0
29
30
31mount_debugfs()
32{
33	if grep -q debugfs /proc/mounts ; then
34		DEBUGFS_WAS_MOUNTED=1
35		DEBUGFS_PATH=$(awk '/debugfs/{print $2}' /proc/mounts)
36		tst_res TINFO "debugfs already mounted at $DEBUGFS_PATH"
37	else
38		if ! grep -q debugfs /proc/filesystems ; then
39			tst_res TCONF "debugfs not supported"
40		fi
41		DEBUGFS_PATH="./tst_debug"
42		mkdir "$DEBUGFS_PATH"
43		if mount -t debugfs xxx "$DEBUGFS_PATH" ; then
44			tst_res TINFO "debugfs mounted at $DEBUGFS_PATH"
45		else
46			tst_res TFAIL "Unable to mount debugfs"
47		fi
48	fi
49}
50
51setup()
52{
53	if tst_kvcmp -lt 2.6.30 ; then
54		tst_brk TCONF "Dynamic debug is available since version 2.6.30"
55	fi
56
57	mount_debugfs
58	if [ ! -d "$DEBUGFS_PATH/dynamic_debug" ] ; then
59		tst_brk TBROK "Unable to find $DEBUGFS_PATH/dynamic_debug"
60	fi
61	DEBUGFS_CONTROL="$DEBUGFS_PATH/dynamic_debug/control"
62	if [ ! -e "$DEBUGFS_CONTROL" ] ; then
63		tst_brk TBROK "Unable to find $DEBUGFS_CONTROL"
64	fi
65
66	# Both patches with changes were backported to RHEL6 kernel 2.6.32-547
67	if tst_kvcmp -ge '3.4 RHEL6:2.6.32-547' ; then
68		NEW_INTERFACE=1
69		EMPTY_FLAG="=_"
70	fi
71
72	grep -v "^#" "$DEBUGFS_CONTROL" > "$DYNDEBUG_STATEMENTS"
73}
74
75do_flag()
76{
77	local FLAG="$1"
78	local OPTION_TO_SET="$2"
79	local OPTION_VALUE="$3"
80
81	if ! echo "$OPTION_TO_SET $OPTION_VALUE $FLAG" > \
82		"$DEBUGFS_CONTROL" ; then
83		tst_res TFAIL "Setting '$OPTION_TO_SET $OPTION_VALUE " \
84			"$FLAG' failed with $?!"
85	fi
86}
87
88do_all_flags()
89{
90	OPTION="$1"
91	ALL_INPUTS="$2"
92
93	for INPUT_LINE in $ALL_INPUTS; do
94		do_flag "+p" "$OPTION" "$INPUT_LINE"
95		if tst_kvcmp -ge 3.2 || [ $NEW_INTERFACE -eq 1 ] ; then
96			do_flag "+flmt" "$OPTION" "$INPUT_LINE"
97			do_flag "-flmt" "$OPTION" "$INPUT_LINE"
98		fi
99		do_flag "-p" "$OPTION" "$INPUT_LINE"
100	done
101
102	if awk -v emp="$EMPTY_FLAG" '$3 != emp' "$DEBUGFS_CONTROL" \
103		| grep -v -q "^#" ; then
104		tst_res TFAIL "Failed to remove all set flags"
105	fi
106}
107
108ddebug_test()
109{
110	dmesg > ./dmesg.old
111
112	DD_FUNCS=$(awk -F " |]" '{print $3}' "$DYNDEBUG_STATEMENTS" \
113		| sort | uniq)
114	DD_FILES=$(awk -F " |:" '{print $1}' "$DYNDEBUG_STATEMENTS" \
115		| sort | uniq)
116	DD_LINES=$(awk -F " |:" '{print $2}' "$DYNDEBUG_STATEMENTS" \
117		| sort | uniq)
118	DD_MODULES=$(awk -F [][] '{print $2}' "$DYNDEBUG_STATEMENTS" \
119		| sort | uniq)
120
121	do_all_flags "func" "$DD_FUNCS"
122	do_all_flags "file" "$DD_FILES"
123	do_all_flags "line" "$DD_LINES"
124	do_all_flags "module" "$DD_MODULES"
125
126	dmesg > ./dmesg.new
127	sed -i -e 1,`wc -l < ./dmesg.old`d ./dmesg.new
128	if grep -q -e "Kernel panic" -e "Oops" -e "general protection fault" \
129		-e "general protection handler: wrong gs" -e "\(XEN\) Panic" \
130		-e "fault" -e "warn" -e "\<BUG\>" ./dmesg.new ; then
131		tst_res TFAIL "Issues found in dmesg!"
132	else
133		tst_res TPASS "Dynamic debug OK"
134	fi
135}
136
137cleanup()
138{
139	if [ -e "$DYNDEBUG_STATEMENTS" ]; then
140		FLAGS_SET=$(awk -v emp="$EMPTY_FLAG" '$3 != emp' $DYNDEBUG_STATEMENTS)
141	fi
142	if [ "$FLAGS_SET" ] ; then
143		FLAG_PREFIX=$([ $NEW_INTERFACE -eq 1 ] && echo "" || echo "+")
144		/bin/echo "$FLAGS_SET" | while read -r FLAG_LINE ; do
145			/bin/echo -n "$FLAG_LINE" \
146				| awk -v prf="$FLAG_PREFIX" -F " |:" \
147				'{print "file "$1" line "$2" "prf $4}' \
148				> "$DEBUGFS_CONTROL"
149		done
150	fi
151	if [ $DEBUGFS_WAS_MOUNTED -eq 0 -a -n "$DEBUGFS_PATH" ] ; then
152		tst_umount "$DEBUGFS_PATH"
153	fi
154}
155
156tst_run
157