├── .gitignore ├── .gitreview ├── COPYING ├── LICENSE ├── Makefile.am ├── README.md ├── ac ├── ar-lib ├── compile ├── config.guess ├── config.sub ├── depcomp ├── install-sh ├── ltmain.sh ├── missing └── test-driver ├── configure.ac ├── doc ├── .gitignore ├── Makefile.am ├── concepts.rst ├── conf.py ├── debugging.rst ├── examples.rst ├── features.rst ├── implementation.rst ├── index.rst ├── installation.rst ├── introduction.rst ├── progref.rst ├── sphinx-static │ └── theme_overrides.css └── sphinx │ ├── cdomain.py │ ├── kernel-doc │ ├── kernel_include.py │ ├── kerneldoc.py │ ├── kfigure.py │ ├── load_config.py │ └── rstFlatTable.py ├── examples ├── Makefile.in ├── h2.c ├── h3.c ├── h4.c ├── hello.c ├── kgdemo.c └── runchecks.cfg ├── kernel ├── .gitignore ├── Makefile.in ├── ktf.h ├── ktf_compat.h ├── ktf_context.c ├── ktf_cov.c ├── ktf_cov.h ├── ktf_debugfs.c ├── ktf_debugfs.h ├── ktf_kallsyms.c ├── ktf_kallsyms.h ├── ktf_map.c ├── ktf_map.h ├── ktf_netctx.c ├── ktf_netctx.h ├── ktf_nl.c ├── ktf_nl.h ├── ktf_override.c ├── ktf_override.h ├── ktf_test.c ├── ktf_test.h ├── ktf_unlproto.h └── runchecks.cfg ├── lib ├── Makefile.am ├── ktf.h ├── ktf_debug.cpp ├── ktf_debug.h ├── ktf_int.cpp ├── ktf_int.h ├── ktf_run.cpp └── ktf_unlproto.c ├── m4 ├── ax_check_compile_flag.m4 ├── ktf.m4 ├── libtool.m4 ├── ltoptions.m4 ├── ltsugar.m4 ├── ltversion.m4 └── lt~obsolete.m4 ├── scripts ├── ktf_syms.mk ├── ktfnew ├── resolve ├── runtests.mk ├── runtests.sh └── top_make.mk ├── selftest ├── Makefile.in ├── context.c ├── context.h ├── context_self.h ├── hybrid.c ├── hybrid.h ├── hybrid_self.h ├── ktf_syms.txt ├── runchecks.cfg └── self.c └── user ├── Makefile.am ├── hybrid.cpp ├── ktfcov.cpp ├── ktfrun.cpp └── ktftest.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | autom4te.cache 4 | aclocal.m4 5 | configure 6 | config.log 7 | config.status 8 | .gdb_history 9 | .deps 10 | .libs 11 | libtool 12 | *.cmd 13 | *.o 14 | *.ko 15 | *.xml 16 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=review.no.oracle.com 3 | port=29418 4 | project=ktf.git 5 | defaultbranch=master 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Kernel Test Framework (KTF) is licenced under: 2 | SPDX-License-Identifier: GPL-2.0 3 | 4 | according with: 5 | 6 | LICENSE 7 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | 3 | ACLOCAL_AMFLAGS= -I m4 4 | 5 | SUBDIRS = kernel selftest examples lib user doc 6 | 7 | documentation htmlhelp htmldocs: 8 | @(cd doc && $(MAKE) htmlhelp) 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kernel Test Framework (KTF) 2 | 3 | KTF is a Google Test-like environment for writing C unit tests for 4 | kernel code. Tests are implemented as kernel modules which declare 5 | each test as part of a test case. The body of each test case 6 | consists of assertions. Tests look like this: 7 | 8 | TEST(examples, hello_ok) 9 | { 10 | EXPECT_TRUE(true); 11 | } 12 | 13 | "examples" is the test case name, "hello_ok" the test. 14 | KTF provides many different types of assertions, see 15 | kernel/ktf.h for the complete list. 16 | 17 | Usually tests are added on test module init via 18 | 19 | ADD_TEST(test_name); 20 | 21 | This registers the test with the KTF framework for later 22 | execution. There are many examples in the examples/ 23 | directory. 24 | 25 | "ktfrun" is provided to execute tests, it communicates 26 | with the KTF kernel module via netlink socket to query 27 | available tests and trigger test execution. 28 | 29 | The design priorities for KTF are to make it 30 | 31 | * easy to run tests. Just ensure the ktf module is loaded, 32 | then load your test module and execute "ktfrun". 33 | 34 | * easy to interpret results. Output from ktfrun is clear 35 | and can be filtered easily. Assertion failures indicate 36 | the line of code where the failure occurred. Results of 37 | the last test run are always available from 38 | /sys/kernel/debug/ktf/results/ 39 | 40 | * easy to add tests. Adding a test takes a few lines of code. 41 | Just (re)build the test module, unload/reload and KTF can 42 | run the test. See the examples/ directory for some hints. 43 | 44 | * easy to analyse test behaviour (code coverage, memory utilization 45 | during test execution). We provide "ktfcov" to support enabling 46 | coverage support on a per-module basis. Coverage data is 47 | available in /sys/kernel/debug/ktf/coverage, showing how often 48 | functions were called during the coverage period, and optionally 49 | any outstanding memory allocations originating from functions 50 | that were subject to coverage. 51 | 52 | All of the above will hopefully help Linux kernel engineers 53 | practice continuous integration and more thoroughly unit test 54 | their code. 55 | 56 | ## User Documentation 57 | 58 | See [./doc](./doc) 59 | 60 | 61 | -------------------------------------------------------------------------------- /ac/ar-lib: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for Microsoft lib.exe 3 | 4 | me=ar-lib 5 | scriptversion=2012-03-01.08; # UTC 6 | 7 | # Copyright (C) 2010-2014 Free Software Foundation, Inc. 8 | # Written by Peter Rosin . 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program. If not, see . 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | # This file is maintained in Automake, please report 29 | # bugs to or send patches to 30 | # . 31 | 32 | 33 | # func_error message 34 | func_error () 35 | { 36 | echo "$me: $1" 1>&2 37 | exit 1 38 | } 39 | 40 | file_conv= 41 | 42 | # func_file_conv build_file 43 | # Convert a $build file to $host form and store it in $file 44 | # Currently only supports Windows hosts. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv in 65 | mingw) 66 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 67 | ;; 68 | cygwin) 69 | file=`cygpath -m "$file" || echo "$file"` 70 | ;; 71 | wine) 72 | file=`winepath -w "$file" || echo "$file"` 73 | ;; 74 | esac 75 | ;; 76 | esac 77 | } 78 | 79 | # func_at_file at_file operation archive 80 | # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE 81 | # for each of them. 82 | # When interpreting the content of the @FILE, do NOT use func_file_conv, 83 | # since the user would need to supply preconverted file names to 84 | # binutils ar, at least for MinGW. 85 | func_at_file () 86 | { 87 | operation=$2 88 | archive=$3 89 | at_file_contents=`cat "$1"` 90 | eval set x "$at_file_contents" 91 | shift 92 | 93 | for member 94 | do 95 | $AR -NOLOGO $operation:"$member" "$archive" || exit $? 96 | done 97 | } 98 | 99 | case $1 in 100 | '') 101 | func_error "no command. Try '$0 --help' for more information." 102 | ;; 103 | -h | --h*) 104 | cat <. 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file lazy 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) LAZY, no conversion will 44 | # take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv/,$2, in 65 | *,$file_conv,*) 66 | ;; 67 | mingw/*) 68 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 69 | ;; 70 | cygwin/*) 71 | file=`cygpath -m "$file" || echo "$file"` 72 | ;; 73 | wine/*) 74 | file=`winepath -w "$file" || echo "$file"` 75 | ;; 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | # func_cl_dashL linkdir 82 | # Make cl look for libraries in LINKDIR 83 | func_cl_dashL () 84 | { 85 | func_file_conv "$1" 86 | if test -z "$lib_path"; then 87 | lib_path=$file 88 | else 89 | lib_path="$lib_path;$file" 90 | fi 91 | linker_opts="$linker_opts -LIBPATH:$file" 92 | } 93 | 94 | # func_cl_dashl library 95 | # Do a library search-path lookup for cl 96 | func_cl_dashl () 97 | { 98 | lib=$1 99 | found=no 100 | save_IFS=$IFS 101 | IFS=';' 102 | for dir in $lib_path $LIB 103 | do 104 | IFS=$save_IFS 105 | if $shared && test -f "$dir/$lib.dll.lib"; then 106 | found=yes 107 | lib=$dir/$lib.dll.lib 108 | break 109 | fi 110 | if test -f "$dir/$lib.lib"; then 111 | found=yes 112 | lib=$dir/$lib.lib 113 | break 114 | fi 115 | if test -f "$dir/lib$lib.a"; then 116 | found=yes 117 | lib=$dir/lib$lib.a 118 | break 119 | fi 120 | done 121 | IFS=$save_IFS 122 | 123 | if test "$found" != yes; then 124 | lib=$lib.lib 125 | fi 126 | } 127 | 128 | # func_cl_wrapper cl arg... 129 | # Adjust compile command to suit cl 130 | func_cl_wrapper () 131 | { 132 | # Assume a capable shell 133 | lib_path= 134 | shared=: 135 | linker_opts= 136 | for arg 137 | do 138 | if test -n "$eat"; then 139 | eat= 140 | else 141 | case $1 in 142 | -o) 143 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 144 | eat=1 145 | case $2 in 146 | *.o | *.[oO][bB][jJ]) 147 | func_file_conv "$2" 148 | set x "$@" -Fo"$file" 149 | shift 150 | ;; 151 | *) 152 | func_file_conv "$2" 153 | set x "$@" -Fe"$file" 154 | shift 155 | ;; 156 | esac 157 | ;; 158 | -I) 159 | eat=1 160 | func_file_conv "$2" mingw 161 | set x "$@" -I"$file" 162 | shift 163 | ;; 164 | -I*) 165 | func_file_conv "${1#-I}" mingw 166 | set x "$@" -I"$file" 167 | shift 168 | ;; 169 | -l) 170 | eat=1 171 | func_cl_dashl "$2" 172 | set x "$@" "$lib" 173 | shift 174 | ;; 175 | -l*) 176 | func_cl_dashl "${1#-l}" 177 | set x "$@" "$lib" 178 | shift 179 | ;; 180 | -L) 181 | eat=1 182 | func_cl_dashL "$2" 183 | ;; 184 | -L*) 185 | func_cl_dashL "${1#-L}" 186 | ;; 187 | -static) 188 | shared=false 189 | ;; 190 | -Wl,*) 191 | arg=${1#-Wl,} 192 | save_ifs="$IFS"; IFS=',' 193 | for flag in $arg; do 194 | IFS="$save_ifs" 195 | linker_opts="$linker_opts $flag" 196 | done 197 | IFS="$save_ifs" 198 | ;; 199 | -Xlinker) 200 | eat=1 201 | linker_opts="$linker_opts $2" 202 | ;; 203 | -*) 204 | set x "$@" "$1" 205 | shift 206 | ;; 207 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 208 | func_file_conv "$1" 209 | set x "$@" -Tp"$file" 210 | shift 211 | ;; 212 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 213 | func_file_conv "$1" mingw 214 | set x "$@" "$file" 215 | shift 216 | ;; 217 | *) 218 | set x "$@" "$1" 219 | shift 220 | ;; 221 | esac 222 | fi 223 | shift 224 | done 225 | if test -n "$linker_opts"; then 226 | linker_opts="-link$linker_opts" 227 | fi 228 | exec "$@" $linker_opts 229 | exit 1 230 | } 231 | 232 | eat= 233 | 234 | case $1 in 235 | '') 236 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 237 | exit 1; 238 | ;; 239 | -h | --h*) 240 | cat <<\EOF 241 | Usage: compile [--help] [--version] PROGRAM [ARGS] 242 | 243 | Wrapper for compilers which do not understand '-c -o'. 244 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 245 | arguments, and rename the output as expected. 246 | 247 | If you are trying to build a whole package this is not the 248 | right script to run: please start by reading the file 'INSTALL'. 249 | 250 | Report bugs to . 251 | EOF 252 | exit $? 253 | ;; 254 | -v | --v*) 255 | echo "compile $scriptversion" 256 | exit $? 257 | ;; 258 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) 259 | func_cl_wrapper "$@" # Doesn't return... 260 | ;; 261 | esac 262 | 263 | ofile= 264 | cfile= 265 | 266 | for arg 267 | do 268 | if test -n "$eat"; then 269 | eat= 270 | else 271 | case $1 in 272 | -o) 273 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 274 | # So we strip '-o arg' only if arg is an object. 275 | eat=1 276 | case $2 in 277 | *.o | *.obj) 278 | ofile=$2 279 | ;; 280 | *) 281 | set x "$@" -o "$2" 282 | shift 283 | ;; 284 | esac 285 | ;; 286 | *.c) 287 | cfile=$1 288 | set x "$@" "$1" 289 | shift 290 | ;; 291 | *) 292 | set x "$@" "$1" 293 | shift 294 | ;; 295 | esac 296 | fi 297 | shift 298 | done 299 | 300 | if test -z "$ofile" || test -z "$cfile"; then 301 | # If no '-o' option was seen then we might have been invoked from a 302 | # pattern rule where we don't need one. That is ok -- this is a 303 | # normal compilation that the losing compiler can handle. If no 304 | # '.c' file was seen then we are probably linking. That is also 305 | # ok. 306 | exec "$@" 307 | fi 308 | 309 | # Name of file we expect compiler to create. 310 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 311 | 312 | # Create the lock directory. 313 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 314 | # that we are using for the .o file. Also, base the name on the expected 315 | # object file name, since that is what matters with a parallel build. 316 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 317 | while true; do 318 | if mkdir "$lockdir" >/dev/null 2>&1; then 319 | break 320 | fi 321 | sleep 1 322 | done 323 | # FIXME: race condition here if user kills between mkdir and trap. 324 | trap "rmdir '$lockdir'; exit 1" 1 2 15 325 | 326 | # Run the compile. 327 | "$@" 328 | ret=$? 329 | 330 | if test -f "$cofile"; then 331 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 332 | elif test -f "${cofile}bj"; then 333 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 334 | fi 335 | 336 | rmdir "$lockdir" 337 | exit $ret 338 | 339 | # Local Variables: 340 | # mode: shell-script 341 | # sh-indentation: 2 342 | # eval: (add-hook 'write-file-hooks 'time-stamp) 343 | # time-stamp-start: "scriptversion=" 344 | # time-stamp-format: "%:y-%02m-%02d.%02H" 345 | # time-stamp-time-zone: "UTC" 346 | # time-stamp-end: "; # UTC" 347 | # End: 348 | -------------------------------------------------------------------------------- /ac/missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /ac/test-driver: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # test-driver - basic testsuite driver script. 3 | 4 | scriptversion=2013-07-13.22; # UTC 5 | 6 | # Copyright (C) 2011-2014 Free Software Foundation, Inc. 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2, or (at your option) 11 | # any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | # As a special exception to the GNU General Public License, if you 22 | # distribute this file as part of a program that contains a 23 | # configuration script generated by Autoconf, you may include it under 24 | # the same distribution terms that you use for the rest of that program. 25 | 26 | # This file is maintained in Automake, please report 27 | # bugs to or send patches to 28 | # . 29 | 30 | # Make unconditional expansion of undefined variables an error. This 31 | # helps a lot in preventing typo-related bugs. 32 | set -u 33 | 34 | usage_error () 35 | { 36 | echo "$0: $*" >&2 37 | print_usage >&2 38 | exit 2 39 | } 40 | 41 | print_usage () 42 | { 43 | cat <$log_file 2>&1 108 | estatus=$? 109 | 110 | if test $enable_hard_errors = no && test $estatus -eq 99; then 111 | tweaked_estatus=1 112 | else 113 | tweaked_estatus=$estatus 114 | fi 115 | 116 | case $tweaked_estatus:$expect_failure in 117 | 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 118 | 0:*) col=$grn res=PASS recheck=no gcopy=no;; 119 | 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 120 | 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; 121 | *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; 122 | *:*) col=$red res=FAIL recheck=yes gcopy=yes;; 123 | esac 124 | 125 | # Report the test outcome and exit status in the logs, so that one can 126 | # know whether the test passed or failed simply by looking at the '.log' 127 | # file, without the need of also peaking into the corresponding '.trs' 128 | # file (automake bug#11814). 129 | echo "$res $test_name (exit status: $estatus)" >>$log_file 130 | 131 | # Report outcome to console. 132 | echo "${col}${res}${std}: $test_name" 133 | 134 | # Register the test result, and other relevant metadata. 135 | echo ":test-result: $res" > $trs_file 136 | echo ":global-test-result: $res" >> $trs_file 137 | echo ":recheck: $recheck" >> $trs_file 138 | echo ":copy-in-global-log: $gcopy" >> $trs_file 139 | 140 | # Local Variables: 141 | # mode: shell-script 142 | # sh-indentation: 2 143 | # eval: (add-hook 'write-file-hooks 'time-stamp) 144 | # time-stamp-start: "scriptversion=" 145 | # time-stamp-format: "%:y-%02m-%02d.%02H" 146 | # time-stamp-time-zone: "UTC" 147 | # time-stamp-end: "; # UTC" 148 | # End: 149 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # Process this file with autoconf to produce a configure script. 2 | 3 | # Prelude. 4 | AC_PREREQ([2.59]) 5 | AC_INIT([ktf], [1.0], [knut.omang@oracle.com]) 6 | 7 | # unique source file --- primitive safety check 8 | AC_CONFIG_SRCDIR([kernel/ktf.h]) 9 | 10 | # place to put some extra build scripts installed 11 | AC_CONFIG_AUX_DIR([ac]) 12 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 13 | 14 | # Look for/generate m4 files under top/m4 15 | AC_CONFIG_MACRO_DIR([m4]) 16 | 17 | AM_INIT_AUTOMAKE([foreign -Wall -Werror]) 18 | 19 | # Silent rules by default - use make V=1 for verbose 20 | AM_SILENT_RULES([yes]) 21 | 22 | 23 | # temporary measure to see if running make sequentially will eliminate some 24 | # spurious build errors: 25 | # NB! this comment is interpreted by terse, keep as is: 26 | # Sequential make 27 | 28 | # Checks for programs. 29 | AC_PROG_CXX 30 | AM_PROG_CC_C_O 31 | 32 | AC_PROG_LIBTOOL 33 | 34 | # Checks for header files. 35 | AC_HEADER_STDC 36 | AC_CHECK_HEADERS([stdlib.h]) 37 | 38 | # Checks for typedefs, structures, and compiler characteristics. 39 | 40 | # Checks for library functions. 41 | AC_FUNC_MALLOC 42 | 43 | AC_ARG_WITH([googletest], AS_HELP_STRING([--with-googletest], [Optional path to a gtest install]), 44 | [gtest_prefix="$withval"],AS_IF([test "x$prefix" != "xNONE" -a "x$prefix" != "x"],[gtest_prefix=$prefix])) 45 | 46 | AM_CONFIG_KTF 47 | AM_KTF_DIR([kernel]) 48 | AM_KTF_DIR([selftest]) 49 | AM_KTF_DIR([examples]) 50 | 51 | AC_CONFIG_FILES([Makefile 52 | kernel/Makefile 53 | selftest/Makefile 54 | examples/Makefile 55 | lib/Makefile 56 | user/Makefile 57 | doc/Makefile 58 | ]) 59 | AC_OUTPUT 60 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = KernelTestFramework 8 | SPHINXSTATIC = sphinx-static 9 | SOURCEDIR = $(srcdir) 10 | BUILDDIR = . 11 | TARGETS = htmlhelp 12 | 13 | docs: htmldocs 14 | 15 | help: 16 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 17 | 18 | # silence Spinx completely unless V=1 19 | # For some reason the htmlhelp target does not produce _sources, while 20 | # the html target does not produce correct next and prev links 21 | # Make both and sync the _sources over 22 | # 23 | htmldocs: $(TARGETS) 24 | 25 | $(TARGETS): Makefile $(srcdir)/*.rst 26 | @if test x$V != x1; then export Q="-q"; echo -n " HTMLDOC $$(pwd)"; fi; \ 27 | $(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $$Q $(SPHINXOPTS) $(O) | \ 28 | if test x$V != x1; then grep -v 'Build finished'; else cat -; fi; \ 29 | $(SPHINXBUILD) -M htmlhelp "$(SOURCEDIR)" "$(BUILDDIR)" $$Q $(SPHINXOPTS) $(O) | \ 30 | if test x$V != x1; then grep -v 'Build finished' || echo ""; else cat -; fi 31 | @rsync -a html/_sources htmlhelp/ 32 | 33 | clean-local: 34 | rm -fr doctrees htmlhelp 35 | -------------------------------------------------------------------------------- /doc/debugging.rst: -------------------------------------------------------------------------------- 1 | 8. Debugging KTF 2 | -------------------- 3 | 4 | Structured debugging/tracing by printf 5 | ====================================== 6 | 7 | The kernel side of KTF implements it's own simple printk based logging 8 | abstraction. You can create log entries by means of calls to the macro 9 | tlog(level, format,...) - level is a bitmask where individual bits 10 | represents log classes. You can read and set this bitmask via a 11 | writable ``/sys`` file:: 12 | 13 | # cat /sys/module/ktf/parameters/debug_mask 14 | 0x1 15 | echo 0x3 > /sys/module/ktf/parameters/debug_mask 16 | # cat /sys/module/ktf/parameters/debug_mask 17 | 0x3 18 | 19 | The default value of ``debug_mask`` is 0x1 = INFO level. 20 | Bits are by convention supposed to be 21 | ordered by verbosity, with the lowest bits reserved for low volume, 22 | important messages, while the higher bist are left for more verbose 23 | debugging. You can also use this mechanism for simple debugging of KTF's 24 | interaction with your tests, as the core KTF code contains some log 25 | statements to make it easier to follow and debug involved 26 | instances of KTF objects. 27 | 28 | Similarly, the user library implementing the interaction with the 29 | user land test runner can log details about this. You can enable such 30 | logging by providing a similar bitmask via the environment variable 31 | KTF_DEBUG_MASK. 32 | 33 | Debugging fatal errors in tests 34 | =============================== 35 | 36 | So your KTF test crashed the kernel? Let's see how you can use crash to 37 | examine KTF test cases, individual test logs and see which test is running. 38 | 39 | First step is we need to load symbols for KTF. To get text, data and 40 | bss section locations for the ktf module (assuming it's currently 41 | loaded):: 42 | 43 | # cd /sys/module/ktf/sections 44 | # cat .text .data .bss 45 | 0xffffffffa0bdb000 46 | 0xffffffffa0bdf000 47 | 0xffffffffa0bdf7a0 48 | 49 | Now run crash on your corefile (or /proc/kcore for a live kernel):: 50 | 51 | # crash 52 | crash> add-symbol-file /path/to/kernel/ktf.ko 0xffffffffa0bdb000 -s .data 0xffffffffa0bdf000 -s .bss 0xffffffffa0bdf7a0 53 | 54 | Now we can see the global test_cases rbtree via the handy 55 | "tree" command. It displays an rbtree, and because test_cases 56 | is an rbtree under the hood we can display the set of test 57 | cases as follows:: 58 | 59 | crash> tree -t rbtree -s ktf_case test_cases 60 | ffff88036f710c00 61 | struct ktf_case { 62 | kmap = { 63 | node = { 64 | __rb_parent_color = 1, 65 | rb_right = 0x0, 66 | rb_left = 0x0 67 | }, 68 | key = "selftest\000cov\000probereturn\000probeentry\000wrongversion\000dummy\000simplemap", 69 | map = 0xffffffffa0bdd1a0 , 70 | refcount = { 71 | refcount = { 72 | counter = 2 73 | } 74 | } 75 | }, 76 | tests = { 77 | root = { 78 | rb_node = 0xffff880250ac4a00 79 | }, 80 | size = 5, 81 | lock = { 82 | { 83 | rlock = { 84 | raw_lock = { 85 | { 86 | head_tail = 655370, 87 | tickets = { 88 | head = 10, 89 | tail = 10 90 | } 91 | } 92 | } 93 | } 94 | } 95 | }, 96 | elem_comparefn = 0x0, 97 | elem_freefn = 0xffffffffa0bd8760 98 | }, 99 | debugfs = { 100 | debugfs_results_testset = 0xffff88021a18a3c0, 101 | debugfs_results_test = 0xffff88021a18aa80, 102 | debugfs_run_testset = 0xffff88021a18a300, 103 | debugfs_run_test = 0xffff88021a18a840 104 | } 105 | } 106 | 107 | Here we had 1 test case - from the "key" field 108 | we can see it is called "selftest" - in fact it is 109 | KTF's self tests. Within that one test cases we see 110 | the rbtree for the indivdual selftest tests has a root 111 | rb_node:: 112 | 113 | tests = { 114 | root = { 115 | rb_node = 0xffff880250ac4a00 116 | }, 117 | 118 | By printing _that_ tree of ktf_test structures from 119 | root node (-N) 0xffff880250ac4a00 we can see our 120 | individual tests:: 121 | 122 | crash> tree -t rbtree -s ktf_test -N 0xffff880250ac4a00 123 | ffff880250ac4a00 124 | struct ktf_test { 125 | kmap = { 126 | node = { 127 | __rb_parent_color = 1, 128 | rb_right = 0xffff880250ac5b00, 129 | rb_left = 0xffff880250ac5d00 130 | }, 131 | key = "probeentry\000wrongversion\000dummy\000simplemap\000\000\000\000\000\020\276\240\377\377\377\377 \020\276\240\377\377\377\377@\020\276\240\377", 132 | map = 0xffff88036f710c68, 133 | refcount = { 134 | refcount = { 135 | counter = 2 136 | } 137 | } 138 | }, 139 | tclass = 0xffffffffa0be41a4 "selftest", 140 | name = 0xffffffffa0be41bd "probeentry", 141 | fun = 0xffffffffa0be1920, 142 | start = 0, 143 | end = 1, 144 | skb = 0xffff88003fc03800, 145 | log = 0xffff88003fa58000 "", 146 | lastrun = { 147 | tv_sec = 1506072537, 148 | tv_nsec = 289494591 149 | }, 150 | debugfs = { 151 | debugfs_results_testset = 0x0, 152 | debugfs_results_test = 0xffff88021a18ac00, 153 | debugfs_run_testset = 0x0, 154 | debugfs_run_test = 0xffff88021a18af00 155 | }, 156 | handle = 0xffffffffa0be5480 157 | } 158 | ffff880250ac5d00 159 | struct ktf_test { 160 | kmap = { 161 | node = { 162 | __rb_parent_color = 18446612142257621505, 163 | rb_right = 0x0, 164 | rb_left = 0xffff880250ac4b00 165 | }, 166 | key = "dummy\000simplemap\000\000\000\000\000\020\276\240\377\377\377\377 \020\276\240\377\377\377\377@\020\276\240\377\377\377\377`\020\276\240\377\377\377\377\200\020\276\240\377\377\377\377\320\020\276\240\377", 167 | map = 0xffff88036f710c68, 168 | refcount = { 169 | refcount = { 170 | counter = 2 171 | } 172 | } 173 | }, 174 | tclass = 0xffffffffa0be41a4 "selftest", 175 | name = 0xffffffffa0be41d5 "dummy", 176 | fun = 0xffffffffa0be10f0, 177 | start = 0, 178 | end = 1, 179 | skb = 0xffff88003fc03800, 180 | log = 0xffff88003fa59800 "", 181 | lastrun = { 182 | tv_sec = 1506072537, 183 | tv_nsec = 289477354 184 | }, 185 | debugfs = { 186 | debugfs_results_testset = 0x0, 187 | debugfs_results_test = 0xffff88021a18a900, 188 | debugfs_run_testset = 0x0, 189 | debugfs_run_test = 0xffff88021a18a9c0 190 | }, 191 | handle = 0xffffffffa0be5480 192 | } 193 | ... 194 | crash> 195 | 196 | 197 | The "log" fields are empty as each test passed, but we can 198 | see from the "lastrun" times when the tests were run. 199 | Logs will contain assertion failures etc in case of failure. 200 | 201 | Note that each test has a "handle" field also - this is 202 | the KTF handle which was used to register the test. Each 203 | handle also shows the currently-executing (if in the middle 204 | of a test run) test associated with it, so if we want to 205 | see where test execution was we can simply print the handle:: 206 | 207 | crash> print *(struct ktf_handle *)0xffffffffa0be5480 208 | $13 = { 209 | test_list = { 210 | next = 0xffffffffa0be5480, 211 | prev = 0xffffffffa0be5480 212 | }, 213 | handle_list = { 214 | next = 0xffffffffa0be5490, 215 | prev = 0xffffffffa0be5490 216 | }, 217 | ctx_map = { 218 | root = { 219 | rb_node = 0x0 220 | }, 221 | size = 0, 222 | lock = { 223 | { 224 | rlock = { 225 | raw_lock = { 226 | { 227 | head_tail = 0, 228 | tickets = { 229 | head = 0, 230 | tail = 0 231 | } 232 | } 233 | } 234 | } 235 | } 236 | }, 237 | elem_comparefn = 0x0, 238 | elem_freefn = 0x0 239 | }, 240 | id = 0, 241 | version = 4294967296, 242 | current_test = 0x0 243 | } 244 | crash> 245 | 246 | In this case current_test is NULL, but if we crashed in the 247 | middle of executing a test it would show us which struct ktf_test * 248 | it was. 249 | -------------------------------------------------------------------------------- /doc/examples.rst: -------------------------------------------------------------------------------- 1 | 6. Example test code 2 | -------------------- 3 | 4 | Here is a minimal dummy example of a KTF unit test suite that defines 5 | two tests, ``hello_ok`` and ``hello_fail``. The test is in the examples 6 | directory and is built with KTF: 7 | 8 | .. literalinclude:: ../examples/hello.c 9 | :language: c 10 | 11 | To run the test, cd to your KTF build tree and insmod the ktf module and 12 | the module that provides the test:: 13 | 14 | insmod kernel/ktf.ko 15 | insmod examples/hello.ko 16 | 17 | Now you should be able to run one or more of the tests by running the 18 | application ``ktfrun`` built in ``user/ktfrun``. You should be able to run 19 | that application as an ordinary user:: 20 | 21 | ktfrun --gtest_list_tests 22 | ktfrun --gtest_filter='*fail' 23 | ktfrun --gtest_filter='*ok' 24 | 25 | There are more examples in the examples directory. KTF also includes a 26 | ``selftest`` directory used to test/check the KTF implementation itself. 27 | -------------------------------------------------------------------------------- /doc/implementation.rst: -------------------------------------------------------------------------------- 1 | 2 | 2. Implementation 3 | ----------------- 4 | 5 | KTF consists of a kernel part and a user part. The role of the user part is to query the kernel 6 | for available tests, and provide mechanisms for executing a selected set or all the available 7 | tests, and report the results. The core ktf kernel module simply provides some APIs to write 8 | assertions and run tests and to communicate about tests and results with user mode. 9 | A simple generic Netlink protocol is used for the communication. 10 | 11 | User mode implementation 12 | ************************ 13 | 14 | Since test filtering and reporting is something existing unit test frameworks for 15 | user space code already does well, the implementation of KTF simply leverages that. 16 | The current version supports an integration with gtest (Googletest), which provides a lot of 17 | these features in a flexible way, but in principle alternative implementations could 18 | use the reporting of any other user level unit test framework. The use of gtest also allows this 19 | documentation to be shorter, as many of the features in gtest are automatically available for KTF as well. 20 | More information about Googletest features can be found here: https://github.com/google/googletest 21 | 22 | Kernel mode implementation 23 | ************************** 24 | 25 | The kernel side of KTF implements a simple API for tracking test modules, 26 | writing tests, support functions and and a set of assertion macros, some 27 | tailored for typical kernel usage, such as ``ASSERT_OK_ADDR_GOTO()`` 28 | as a kernel specific macro to check for a valid address with a label to jump to if the 29 | assertion fails. After all as we are still in the kernel, tests would always need to clean up for 30 | themselves even though in the context of ktf. 31 | 32 | KTF supports two distinct classes of tests: 33 | 34 | * Pure kernel mode tests 35 | * Hybrid tests 36 | 37 | Pure kernel mode tests are tests that are fully implemented in kernel space. 38 | This is the most straightforward mode and resembles ordinary user land unit testing 39 | in kernel mode. If you only have kernel mode tests, you will only ever need one user level program 40 | similar to user/ktfrun.cpp, since all test development takes place on the kernel side. 41 | 42 | Hybrid tests are for testing and making assumptions about the user/kernel communication, for instance 43 | if a parameter supplied from user mode is interpreted the intended way when it arrives at it's kernel 44 | destination. For such tests you need to tell ktf (from user space) when the kernel part of the test 45 | is going to be executed - this can happen multiple times depending on your test needs. 46 | Apart from that it works mostly like a normal gtest user level test. 47 | 48 | Kernel integration of KTF or KTF as a separate git project? 49 | *********************************************************** 50 | 51 | Yes. A lot of test infrastructure and utilities for the Linux kernel 52 | is implemented as part of the linux kernel git project. 53 | This has some obvious benefits, such as 54 | 55 | * Always being included 56 | * When APIs are changed, test code can be updated atomically with the rest of the kernel 57 | * Higher visibility and easier access 58 | * Easier integration with internal kernel interfaces useful for testing. 59 | 60 | On the other hand providing KTF as a separate project allows 61 | 62 | * With some use of ``KERNEL_VERSION`` and ``LINUX_VERSION_CODE``, up-to-date KTF code and tests 63 | can be allowed to work across kernel versions. 64 | * This in turn allows a single set of newly developed tests to be 65 | simultaneously tested against multiple older kernels, possibly 66 | detecting more bugs, or instances of bugs not backported. 67 | 68 | So we will continue to support both, and have work in progress to simplify 69 | the maintenance and synchronization of the two versions, and allow the 70 | additional tooling to extend to KTF client test suites as well. 71 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | Kernel Test Framework documentation 2 | =================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | introduction 8 | implementation 9 | features 10 | installation 11 | concepts 12 | examples 13 | progref 14 | debugging 15 | -------------------------------------------------------------------------------- /doc/installation.rst: -------------------------------------------------------------------------------- 1 | 4. Building and installing KTF 2 | ------------------------------ 3 | 4 | KTF's user land side depends on googletest. 5 | The googletest project has seen some structural changes in moving from a 6 | project specific gtest-config via no package management support at all to 7 | recently introduce pkgconfig support. This version of KTF only supports 8 | building against a googletest (gtest) with pkgconfig support, which means 9 | that as of February 2018 you have to build googletest from source at 10 | github. 11 | 12 | Googletest has also recently been fairly in flux, and while we 13 | try to keep up to date with the official googletest version on Github, 14 | we have seen issues with changes that breaks KTF. We also have a small 15 | queue of enhancements and fixes to Googletest based on our experience 16 | and use of it a.o. with KTF. You can find the latest rebase of this 17 | version in the ktf branch of knuto/googletest at Github, but expect it 18 | to rebase as we move forward to keep it up-to-date. 19 | This version will at any time have been tested with KTF by us, since 20 | we use it internally. Let's assume for the rest of these instructions 21 | that your source trees are below ``~/src`` and your build trees are 22 | under ``~/build``:: 23 | 24 | cd ~/src 25 | git clone https://github.com/knuto/googletest.git 26 | 27 | or:: 28 | 29 | cd ~/src 30 | git clone https://github.com/google/googletest.git 31 | 32 | then:: 33 | 34 | mkdir -p ~/build/$(uname -r) 35 | cd ~/build/$(uname -r) 36 | mkdir googletest 37 | cd googletest 38 | cmake ~/src/googletest 39 | make 40 | sudo make install 41 | 42 | Default for googletest is to use static libraries. If you want to use shared 43 | libraries for googletest, you can specify ``-DBUILD_SHARED_LIBS=ON`` to 44 | cmake. If you don't want to install googletest into /usr/local, you can 45 | specify an alternate install path using ``-DCMAKE_INSTALL_PREFIX=`` 46 | to cmake for googletest, and similarly use ``--prefix=`` both for 47 | KTF and your own test modules. Note that on some distros, cmake version 48 | 2 and 3 comes as different packages, make sure you get version 3, which may 49 | require you to use ``cmake3`` as command instead of cmake above. 50 | 51 | Building the standalone version of KTF 52 | ************************************** 53 | 54 | To build KTF from the standalone KTF git project, 55 | cd to your source tree then clone the ktf project:: 56 | 57 | cd ~/src 58 | 59 | cd ktf 60 | autoreconf 61 | 62 | Create a build directory somewhere outside the source tree to allow the 63 | same KTF source tree to be used against multiple versions of the 64 | kernel. Note that the configure command needs to use an absolute path - 65 | relative paths are not supported. 66 | Assuming for simplicity that you want to build for the running 67 | kernel but you can build for any installed ``kernel-*-devel``:: 68 | 69 | cd ~/build/$(uname -r) 70 | mkdir ktf 71 | cd ktf 72 | ~/src/ktf/configure KVER=$(uname -r) 73 | make 74 | 75 | Now you should have got a ``kernel/ktf.ko`` that works with your test kernel 76 | and modules for the ``examples`` and KTF ``selftest`` directories. 77 | Kernel objects will be installed under ``kernel/``. 78 | 79 | Setting up your own test suite based on KTF 80 | ******************************************* 81 | You are now ready to create your own test modules based on KTF. 82 | KTF provides a script for setting up KTF based modules in a similar 83 | way as KTF, using the autotools measures implemented in KTF. The script 84 | assumes for simplicity that you want to have your source tree beside the 85 | ktf source:: 86 | 87 | ~/src/ktf/scripts/ktfnew mysuite 88 | 89 | Now go ahead and write your own kernel tests in ``~/src/mysuite/kernel``, then 90 | similarly to KTF, build your new project with:: 91 | 92 | cd ~/build/$(uname -r) 93 | mkdir mysuite 94 | cd mysuite 95 | ~/src/mysuite/configure KVER=$(uname -r) 96 | make 97 | 98 | By default, dependencies of KTF configured this way will depend directly on the 99 | KTF build tree, which is convenient during development. 100 | KTF also supports the ``install`` target, to allow KTF and test modules to 101 | be built and maintained more independently (dynamic linker support via library 102 | paths instead of -rpath etc). To set up your environment this way do as 103 | follows:: 104 | 105 | cd ~/build/$(uname -r)/ktf 106 | sudo make install 107 | cd ~/build/$(uname -r)/mysuite 108 | ~/src/mysuite/configure KVER=$(uname -r) --with-ktf=/usr/local 109 | make 110 | 111 | Options for configuring against a kernel base 112 | ********************************************* 113 | The default configuration approach using ``KVER`` as sketched above is used to 114 | configure against a prebuilt kernel. KTF also supports configuring against a 115 | development kernel build tree. This can be a full in-source kernel build tree, 116 | or a separate built tree created using the kernel's ``make O=`` 117 | method of building of-of-source. Instead of using ``KVER``, instead let 118 | ``KDIR`` point to the root directory of the desired kernel build tree:: 119 | 120 | cd ~/build/$(uname -r)/ktf 121 | ~/src/ktf/configure KDIR=$HOME/build/kernel 122 | make 123 | -------------------------------------------------------------------------------- /doc/introduction.rst: -------------------------------------------------------------------------------- 1 | :Author: Knut Omang 2 | :Last Updated: Alan Maguire 3 | 4 | 1. Background and motivation 5 | ---------------------------- 6 | 7 | Kernel Test Framework (KTF) implements a unit test framework for the Linux kernel. 8 | There's a wide selection of unit test frameworks available for normal user land 9 | code testing, but we have so far not seen any similar frameworks that can be used 10 | with kernel code, to test details of both exported and non-exported kernel APIs. 11 | The hope is that providing an easy to use and convenient way to write simple unit 12 | tests for kernel internals, that this can promote a more test driven approach to 13 | kernel development, where appropriate. 14 | 15 | An important design goal is to make KTF in a way that it lend itself well to a normal kernel 16 | developer cycle, and that it integrates well with user land unit testing, to allow kernel and 17 | user land tests to behave, look and feel as similar as possible. This should hopefully make it 18 | more intuitive to use as well as more rewarding. We also believe that even a kernel test that 19 | passes should have a nice, easy to read and pleasant output, and that a test framework must have 20 | good observability, that is good mechanisms for debugging what went wrong, both in case of bugs 21 | in the tests and and the test framework itself. 22 | 23 | KTF is designed to test the kernel in the same ways it runs. This means we want to stay away from 24 | changing configuration options, or otherwise make changes that makes it hard to logically tell 25 | from a high level perspective whether the kernel with KTF is really logically "the same" as the 26 | kernel our users are exposed to. Of course we all know that it is very hard to test anything 27 | without affecting it, with quantum mechanics as the extreme, but at least we want to make an 28 | effort to make the footprint as small as possible. 29 | 30 | KTF tests kernel code by running tests in kernel context - or in the case of hybrid tests - in 31 | both user- and kernel contexts. Doing this ensures that we test kernel codepaths in a real way, 32 | without emulating a kernel execution environment. This gives us vastly more control over what 33 | tests can do versus user-space driven testing, and increases confidence that what the tests test 34 | matches what the kernel does since the test execution environment is identical. 35 | 36 | KTF is a product of a refactoring of code used as part of test driven development of a Linux 37 | driver for an Infiniband HCA. It is in active use for kernel component testing within Oracle. 38 | 39 | Test driven development 40 | *********************** 41 | 42 | Unit testing is an important component of Test driven development (TDD). 43 | The idea of test driven development is that when you have some code to write, 44 | whether it is a bug to fix, or a new feature or enhancement, that you start by writing 45 | one or more tests for it, have those tests fail, and then do the actual development. 46 | 47 | Typically a test driven development cycle would have several rounds of development and 48 | test using the new unit tests, and once the (new) tests pass, you would 49 | also run all or a suitable subset (limited by execution time) of the old tests to verify 50 | that you have not broken any old functionality by the new code. 51 | 52 | At this stage it is important that the tests that are run can be run quickly to allow 53 | them to be actively used in the development cycle. When time comes for 54 | submission of the code, a full, extensive set of both the tests the developer thinks 55 | can touch the affected code *and* all the other tests should be run, and a longer time 56 | to run tests can be afforded. 57 | 58 | KTF tries to support this by using the module system of the kernel to support 59 | modularized test suites, where a user only need to insmod the test subsets that he/she wants 60 | to use right then. Different test suites may touch and require different kernel APIs and have 61 | lots of different module and device requirements. To enable as much reuse of the functionality 62 | of code developed within KTF it is important that any piece of test code has as few dependencies 63 | as possible. 64 | 65 | Good use cases for KTF 66 | ********************** 67 | 68 | Unit testing is at it's most valuable when the code to test is relatively error prone, but still 69 | might be difficult to test in a systematic and reproducable way from a normal application level. 70 | It can be difficult to trigger corner cases from a high abstraction layer, 71 | the code paths we want to exercise might only be used occasionally, or we want to exercise 72 | that error/exception scenarios are handled gracefully. 73 | 74 | KTF comes to it's strength in testing kernel APIs that are fairly integrated into the kernel, 75 | and depend upon lots of components, making them difficult or error prone to mock. Good examples 76 | are module APIs not easily testable from user land. Exported module APIs are usually only used 77 | by one or a few other kernel clients, and hitting buggy corner cases with these might be hard or 78 | impossible. This typically leads to bugs detected "down the road", when some new client appears 79 | and starts using the API in a new way, or instabilities that go undetected because underlying 80 | semantics that the implementation implicitly depend upon changes in subtle ways. 81 | 82 | KTF can use mechanisms such as KTF probes in cases where calls to other functions needs to be 83 | intercepted and/or modified to create the right test condition, whether it means waiting for a 84 | potential race condition to occur, or return an error value, or just collect state to make assertions. 85 | 86 | Typical classical use cases that lend itself well to unit testing are simple APIs with a relativ 87 | complex implementation - such as container implementations. Typical kernel examples of these 88 | in the kernel are scatterlist, rbtree, list, XArray etc. When testing the base implementations of such 89 | containers, bringing them entirely out into user space and compiling them standalone require some 90 | additional work up-front to implement mock interfaces to the services provided by the kernel, 91 | but may nonetheless be rewarding in the longer run, as such tests have at it's disposal the whole 92 | arsenal of user land tools, such as gdb, valgrind etc. This, however does not guarantee against 93 | wrong use of a container, such as with interactions between a container and a driver 94 | datastructure. 95 | 96 | Testing the *instantiations* of these container implementations inside drivers or 97 | the kernels's own internals might not be that easy with a user land approach, as it very quickly 98 | requires a prohibitive amount of mock interfaces to be written. And even when such mock 99 | interfaces can be written, one cannot be sure that they implement exactly the same as the 100 | environment that the code executes in within the kernel. Having the ability to make tests within 101 | a release kernel, even run the same tests against multiple such kernels is something KTF 102 | supports well. Our experience is that even error scenarios that are hard to reproduce by 103 | running applications on the kernel can often be reproduced with a surprisingly small 104 | number of lines of code in a KTF test, once the problem is understood. And writing that code can 105 | be a very rewarding way of narrowing down a hard bug. 106 | 107 | When *not* to use KTF 108 | ********************* 109 | 110 | Writing kernel code has some challenges compared to user land code. 111 | KTF is intended for the cases where it is not easy to get coverage by writing 112 | simple tests from user land, using an existing rich and well proven user land unit test 113 | framework. 114 | 115 | Why *you* would want to write and run KTF tests 116 | *********************************************** 117 | 118 | Besides the normal write test, write code, run test cycle of development and the obvious benefits of 119 | delivering better quality code with fewer embarrassments, there's a few other upsides from 120 | developing unit test for a particular area of the kernel: 121 | 122 | * A test becomes an invariant for how the code is supposed to work. 123 | If someone breaks it, they should detect it and either document the changes that caused the breakage 124 | by fixing the test or realize that their fix is broken before you even get to spend time on it. 125 | 126 | * Kernel documentation while quite good in some places, does not always 127 | cover the full picture, or you might not find that sentence you needed while looking for it. 128 | If you want to better understand how a particular kernel module actually works, a good way is to 129 | write a test that codes your assumptions. If it passes, all is well, if not, then you have gained some 130 | understanding of the kernel. 131 | 132 | * Sometimes you may find yourself relying on some specific feature or property of the kernel. 133 | If you encode a test that guards the assumptions you have made, you will capture if someone 134 | changes it, or if your code is ported to an older kernel which does not support it. 135 | -------------------------------------------------------------------------------- /doc/progref.rst: -------------------------------------------------------------------------------- 1 | 7. KTF programming reference 2 | ---------------------------- 3 | 4 | KTF itself contains no tests but provides primitives and data structures to 5 | allow tests to be maintained and written in separate test modules that 6 | depend on the KTF APIs. 7 | 8 | KTF API Overview 9 | **************** 10 | 11 | For reference, the following table lists a few terms and classes of 12 | abstractions provided by KTF. These are kernel side, if not otherwise noted: 13 | 14 | +----------------------------+--------------------------------------------------+ 15 | | **Item** | **description** | 16 | +============================+==================================================+ 17 | | Test module | A kernel object file (.ko) with ktf tests in it | 18 | +----------------------------+--------------------------------------------------+ 19 | | struct ktf_handle | At least 1 per test module. | 20 | | | Use macros KTF_INIT() and KTF_CLEANUP() to set up| 21 | | | and tear down handles. | 22 | +----------------------------+--------------------------------------------------+ 23 | | struct ktf_context | 0-n per test module - test module specific | 24 | | | context for the test, such as eg. a device or | 25 | | | another kernel object. | 26 | +----------------------------+--------------------------------------------------+ 27 | | KTF_INIT() | Call this at the global level in the main file | 28 | | | for each test module. Declares an implicit, | 29 | | | default test handle used by macros which do not | 30 | | | provide a handle argument. | 31 | +----------------------------+--------------------------------------------------+ 32 | | KTF_CTX_INIT() | Use this instead of KTF_INIT if the tests require| 33 | | | a context to execute. Tests will only show up as | 34 | | | options if a context has been provided. | 35 | +----------------------------+--------------------------------------------------+ 36 | | KTF_HANDLE_INIT(handle) | Declare a named handle to associate tests and | 37 | | | contexts with. This is an alternative to | 38 | | | KTF_INIT() to allow the use of separate test | 39 | | | handles for separate sets of tests. | 40 | +----------------------------+--------------------------------------------------+ 41 | | KTF_HANDLE_CTX_INIT(handle)| Equivalent of KTF_CTX_INIT for a named handle | 42 | +----------------------------+--------------------------------------------------+ 43 | | KTF_CLEANUP() | Call this in the __exit function to clean up | 44 | +----------------------------+--------------------------------------------------+ 45 | | KTF_CONTEXT_ADD(ctx, name) | Add a new context to the default handle | 46 | +----------------------------+--------------------------------------------------+ 47 | | KTF_CONTEXT_FIND(name) | Return a struct ktf_context reference to context | 48 | | | 'name', if it exists | 49 | +----------------------------+--------------------------------------------------+ 50 | | KTF_CONTEXT_GET(name,type) | Return the structure of type 'type' containing | 51 | | | the ktf_context named 'name', if 'name' exists. | 52 | +----------------------------+--------------------------------------------------+ 53 | | KTF_CONTEXT_REMOVE(ctx) | Remove a previously added context from KTF | 54 | +----------------------------+--------------------------------------------------+ 55 | | EXPECT_* | non-fatal assertions | 56 | +----------------------------+--------------------------------------------------+ 57 | | ASSERT_* | "fatal" assertions that would cause return/goto | 58 | +----------------------------+--------------------------------------------------+ 59 | | TEST(s, n) {...} | Define a simple test named 's.n' with implicit | 60 | | | arguments 'ctx' and '_i' for context/iteration. | 61 | +----------------------------+--------------------------------------------------+ 62 | | DECLARE_F(f) {...} | Declare a new test fixture named 'f' with | 63 | | | additional data structure | 64 | +----------------------------+--------------------------------------------------+ 65 | | SETUP_F(f, s) {...} | Define setup function for the fixture | 66 | +----------------------------+--------------------------------------------------+ 67 | | TEARDOWN_F(f, t) {...} | Define teardown function for the fixture | 68 | +----------------------------+--------------------------------------------------+ 69 | | INIT_F(f, s, t) {...} | Declare the setup and tear down functions for the| 70 | | | fixture | 71 | +----------------------------+--------------------------------------------------+ 72 | | TEST_F(s, f, n) {...} | Define a test named 's.n' operating in fixture f | 73 | +----------------------------+--------------------------------------------------+ 74 | | ADD_TEST(n) | Add a test previously declared with TEST or | 75 | | | TEST_F to the default handle. | 76 | +----------------------------+--------------------------------------------------+ 77 | | ADD_LOOP_TEST(n, from, to) | Add a test to be executed repeatedly with a range| 78 | | | of values [from,to] to the implicit variable _i | 79 | +----------------------------+--------------------------------------------------+ 80 | | DEL_TEST(n) | Remove a test previously added with ADD_TEST | 81 | +----------------------------+--------------------------------------------------+ 82 | | KTF_ENTRY_PROBE(f, h) | Define function entry probe for function f with | 83 | | {...} | handler function h. Must be used at global level.| 84 | +----------------------------+--------------------------------------------------+ 85 | | KTF_ENTRY_PROBE_RETURN(r) | Return from probed function with return value r. | 86 | | | Must be called within KTF_ENTRY_PROBE(). | 87 | +----------------------------+--------------------------------------------------+ 88 | | KTF_REGISTER_ENTRY_PROBE | Enable probe on entry to kernel function f | 89 | | (f, h) | with handler h. | 90 | +----------------------------+--------------------------------------------------+ 91 | | KTF_UNREGISTER_ENTRY_PROBE | Disable probe on entry to kernel function f | 92 | | (f, h) | which used handler h. | 93 | +----------------------------+--------------------------------------------------+ 94 | | KTF_RETURN_PROBE(f, h) | Define function return probe for function f with | 95 | | {..} | handler h. Must be used at a global level. | 96 | +----------------------------+--------------------------------------------------+ 97 | | KTF_RETURN_VALUE() | Retrieve return value in body of return probe. | 98 | +----------------------------+--------------------------------------------------+ 99 | | KTF_REGISTER_RETURN_PROBE | Enable probe for return of function f with | 100 | | (f, h) | handler h. | 101 | +----------------------------+--------------------------------------------------+ 102 | | KTF_UNREGISTER_RETURN_PROBE| Disable probe for return of function f and | 103 | | (f, h) | handler h. | 104 | +----------------------------+--------------------------------------------------+ 105 | | ktf_cov_enable(m, flags) | Enable coverage analytics for module m. | 106 | | | Flag must be either 0 or KTF_COV_OPT_MEM. | 107 | +----------------------------+--------------------------------------------------+ 108 | | ktf_cov_disable(m) | Disable coverage analytics for module m. | 109 | +----------------------------+--------------------------------------------------+ 110 | | KTF_THREAD_INIT(name, t) | Initialize thread name, struct ktf_thread * t. | 111 | +----------------------------+--------------------------------------------------+ 112 | | KTF_THREAD_RUN(t) | Run initialized struct ktf_thread * t. | 113 | +----------------------------+--------------------------------------------------+ 114 | | KTF_THREAD_STOP(t) | Stop thread via kthread_stop() | 115 | +----------------------------+--------------------------------------------------+ 116 | | KTF_THREAD_WAIT_STARTED(t) | Wait for start of struct ktf_thread * t. | 117 | +----------------------------+--------------------------------------------------+ 118 | | KTF_THREAD_WAIT_COMPLETED | Wait for completion of struct ktf_thread * t. | 119 | | (t) | | 120 | +----------------------------+--------------------------------------------------+ 121 | | HTEST(s, n) { ... } | Declares a hybrid test. A correspondingly named | 122 | | (NB! User mode only!) | test must be declared using TEST() from kernel | 123 | | | space for the hybrid test to be executed. | 124 | +----------------------------+--------------------------------------------------+ 125 | | KTF_USERDATA(self, type, d)| Declare/get a pointer to user/kernel aux.data | 126 | | (NB! both kernel and | for a test that declares such extra data. Used | 127 | | user space!) | for hybrid tests. | 128 | +----------------------------+--------------------------------------------------+ 129 | 130 | The ``KTF_INIT()`` macro must be called at a global level as it just 131 | defines a variable ``__test_handle`` which is referred to, and which existence 132 | is assumed to continue until the call to KTF_CLEANUP(), typically done in 133 | the ``__exit`` function of the test module. 134 | 135 | 136 | 137 | Assertions 138 | ********** 139 | 140 | Below is example documentation for some of the available assertion macros. 141 | For a full overview, see ``kernel/ktf.h`` 142 | 143 | .. kernel-doc:: kernel/ktf.h 144 | :internal: 145 | -------------------------------------------------------------------------------- /doc/sphinx-static/theme_overrides.css: -------------------------------------------------------------------------------- 1 | /* -*- coding: utf-8; mode: css -*- 2 | * 3 | * Sphinx HTML theme customization: read the doc 4 | * 5 | */ 6 | 7 | /* Improve contrast and increase size for easier reading. */ 8 | 9 | body { 10 | font-family: serif; 11 | color: black; 12 | font-size: 100%; 13 | } 14 | 15 | h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend { 16 | font-family: sans-serif; 17 | } 18 | 19 | .wy-menu-vertical li.current a { 20 | color: #505050; 21 | } 22 | 23 | .wy-menu-vertical li.on a, .wy-menu-vertical li.current > a { 24 | color: #303030; 25 | } 26 | 27 | div[class^="highlight"] pre { 28 | font-family: monospace; 29 | color: black; 30 | font-size: 100%; 31 | } 32 | 33 | .wy-menu-vertical { 34 | font-family: sans-serif; 35 | } 36 | 37 | .c { 38 | font-style: normal; 39 | } 40 | 41 | p { 42 | font-size: 100%; 43 | } 44 | 45 | /* Interim: Code-blocks with line nos - lines and line numbers don't line up. 46 | * see: https://github.com/rtfd/sphinx_rtd_theme/issues/419 47 | */ 48 | 49 | div[class^="highlight"] pre { 50 | line-height: normal; 51 | } 52 | .rst-content .highlight > pre { 53 | line-height: normal; 54 | } 55 | 56 | @media screen { 57 | 58 | /* content column 59 | * 60 | * RTD theme's default is 800px as max width for the content, but we have 61 | * tables with tons of columns, which need the full width of the view-port. 62 | */ 63 | 64 | .wy-nav-content{max-width: none; } 65 | 66 | /* table: 67 | * 68 | * - Sequences of whitespace should collapse into a single whitespace. 69 | * - make the overflow auto (scrollbar if needed) 70 | * - align caption "left" ("center" is unsuitable on vast tables) 71 | */ 72 | 73 | .wy-table-responsive table td { white-space: normal; } 74 | .wy-table-responsive { overflow: auto; } 75 | .rst-content table.docutils caption { text-align: left; font-size: 100%; } 76 | 77 | /* captions: 78 | * 79 | * - captions should have 100% (not 85%) font size 80 | * - hide the permalink symbol as long as link is not hovered 81 | */ 82 | 83 | .toc-title { 84 | font-size: 150%; 85 | font-weight: bold; 86 | } 87 | 88 | caption, .wy-table caption, .rst-content table.field-list caption { 89 | font-size: 100%; 90 | } 91 | caption a.headerlink { opacity: 0; } 92 | caption a.headerlink:hover { opacity: 1; } 93 | 94 | /* Menu selection and keystrokes */ 95 | 96 | span.menuselection { 97 | color: blue; 98 | font-family: "Courier New", Courier, monospace 99 | } 100 | 101 | code.kbd, code.kbd span { 102 | color: white; 103 | background-color: darkblue; 104 | font-weight: bold; 105 | font-family: "Courier New", Courier, monospace 106 | } 107 | 108 | /* fix bottom margin of lists items */ 109 | 110 | .rst-content .section ul li:last-child, .rst-content .section ul li p:last-child { 111 | margin-bottom: 12px; 112 | } 113 | 114 | /* inline literal: drop the borderbox, padding and red color */ 115 | 116 | code, .rst-content tt, .rst-content code { 117 | color: inherit; 118 | border: none; 119 | padding: unset; 120 | background: inherit; 121 | font-size: 85%; 122 | } 123 | 124 | .rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal { 125 | color: inherit; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /doc/sphinx/cdomain.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8; mode: python -*- 2 | # pylint: disable=W0141,C0113,C0103,C0325 3 | u""" 4 | cdomain 5 | ~~~~~~~ 6 | 7 | Replacement for the sphinx c-domain. 8 | 9 | :copyright: Copyright (C) 2016 Markus Heiser 10 | :license: GPL Version 2, June 1991 see Linux/COPYING for details. 11 | 12 | List of customizations: 13 | 14 | * Moved the *duplicate C object description* warnings for function 15 | declarations in the nitpicky mode. See Sphinx documentation for 16 | the config values for ``nitpick`` and ``nitpick_ignore``. 17 | 18 | * Add option 'name' to the "c:function:" directive. With option 'name' the 19 | ref-name of a function can be modified. E.g.:: 20 | 21 | .. c:function:: int ioctl( int fd, int request ) 22 | :name: VIDIOC_LOG_STATUS 23 | 24 | The func-name (e.g. ioctl) remains in the output but the ref-name changed 25 | from 'ioctl' to 'VIDIOC_LOG_STATUS'. The function is referenced by:: 26 | 27 | * :c:func:`VIDIOC_LOG_STATUS` or 28 | * :any:`VIDIOC_LOG_STATUS` (``:any:`` needs sphinx 1.3) 29 | 30 | * Handle signatures of function-like macros well. Don't try to deduce 31 | arguments types of function-like macros. 32 | 33 | """ 34 | 35 | from docutils import nodes 36 | from docutils.parsers.rst import directives 37 | 38 | import sphinx 39 | from sphinx import addnodes 40 | from sphinx.domains.c import c_funcptr_sig_re, c_sig_re 41 | from sphinx.domains.c import CObject as Base_CObject 42 | from sphinx.domains.c import CDomain as Base_CDomain 43 | 44 | __version__ = '1.0' 45 | 46 | # Get Sphinx version 47 | major, minor, patch = sphinx.version_info[:3] 48 | 49 | def setup(app): 50 | 51 | app.override_domain(CDomain) 52 | 53 | return dict( 54 | version = __version__, 55 | parallel_read_safe = True, 56 | parallel_write_safe = True 57 | ) 58 | 59 | class CObject(Base_CObject): 60 | 61 | """ 62 | Description of a C language object. 63 | """ 64 | option_spec = { 65 | "name" : directives.unchanged 66 | } 67 | 68 | def handle_func_like_macro(self, sig, signode): 69 | u"""Handles signatures of function-like macros. 70 | 71 | If the objtype is 'function' and the the signature ``sig`` is a 72 | function-like macro, the name of the macro is returned. Otherwise 73 | ``False`` is returned. """ 74 | 75 | if not self.objtype == 'function': 76 | return False 77 | 78 | m = c_funcptr_sig_re.match(sig) 79 | if m is None: 80 | m = c_sig_re.match(sig) 81 | if m is None: 82 | raise ValueError('no match') 83 | 84 | rettype, fullname, arglist, _const = m.groups() 85 | arglist = arglist.strip() 86 | if rettype or not arglist: 87 | return False 88 | 89 | arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup 90 | arglist = [a.strip() for a in arglist.split(",")] 91 | 92 | # has the first argument a type? 93 | if len(arglist[0].split(" ")) > 1: 94 | return False 95 | 96 | # This is a function-like macro, it's arguments are typeless! 97 | signode += addnodes.desc_name(fullname, fullname) 98 | paramlist = addnodes.desc_parameterlist() 99 | signode += paramlist 100 | 101 | for argname in arglist: 102 | param = addnodes.desc_parameter('', '', noemph=True) 103 | # separate by non-breaking space in the output 104 | param += nodes.emphasis(argname, argname) 105 | paramlist += param 106 | 107 | return fullname 108 | 109 | def handle_signature(self, sig, signode): 110 | """Transform a C signature into RST nodes.""" 111 | 112 | fullname = self.handle_func_like_macro(sig, signode) 113 | if not fullname: 114 | fullname = super(CObject, self).handle_signature(sig, signode) 115 | 116 | if "name" in self.options: 117 | if self.objtype == 'function': 118 | fullname = self.options["name"] 119 | else: 120 | # FIXME: handle :name: value of other declaration types? 121 | pass 122 | return fullname 123 | 124 | def add_target_and_index(self, name, sig, signode): 125 | # for C API items we add a prefix since names are usually not qualified 126 | # by a module name and so easily clash with e.g. section titles 127 | targetname = 'c.' + name 128 | if targetname not in self.state.document.ids: 129 | signode['names'].append(targetname) 130 | signode['ids'].append(targetname) 131 | signode['first'] = (not self.names) 132 | self.state.document.note_explicit_target(signode) 133 | inv = self.env.domaindata['c']['objects'] 134 | if (name in inv and self.env.config.nitpicky): 135 | if self.objtype == 'function': 136 | if ('c:func', name) not in self.env.config.nitpick_ignore: 137 | self.state_machine.reporter.warning( 138 | 'duplicate C object description of %s, ' % name + 139 | 'other instance in ' + self.env.doc2path(inv[name][0]), 140 | line=self.lineno) 141 | inv[name] = (self.env.docname, self.objtype) 142 | 143 | indextext = self.get_index_text(name) 144 | if indextext: 145 | if major == 1 and minor < 4: 146 | # indexnode's tuple changed in 1.4 147 | # https://github.com/sphinx-doc/sphinx/commit/e6a5a3a92e938fcd75866b4227db9e0524d58f7c 148 | self.indexnode['entries'].append( 149 | ('single', indextext, targetname, '')) 150 | else: 151 | self.indexnode['entries'].append( 152 | ('single', indextext, targetname, '', None)) 153 | 154 | class CDomain(Base_CDomain): 155 | 156 | """C language domain.""" 157 | name = 'c' 158 | label = 'C' 159 | directives = { 160 | 'function': CObject, 161 | 'member': CObject, 162 | 'macro': CObject, 163 | 'type': CObject, 164 | 'var': CObject, 165 | } 166 | -------------------------------------------------------------------------------- /doc/sphinx/kernel_include.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8; mode: python -*- 3 | # pylint: disable=R0903, C0330, R0914, R0912, E0401 4 | 5 | u""" 6 | kernel-include 7 | ~~~~~~~~~~~~~~ 8 | 9 | Implementation of the ``kernel-include`` reST-directive. 10 | 11 | :copyright: Copyright (C) 2016 Markus Heiser 12 | :license: GPL Version 2, June 1991 see linux/COPYING for details. 13 | 14 | The ``kernel-include`` reST-directive is a replacement for the ``include`` 15 | directive. The ``kernel-include`` directive expand environment variables in 16 | the path name and allows to include files from arbitrary locations. 17 | 18 | .. hint:: 19 | 20 | Including files from arbitrary locations (e.g. from ``/etc``) is a 21 | security risk for builders. This is why the ``include`` directive from 22 | docutils *prohibit* pathnames pointing to locations *above* the filesystem 23 | tree where the reST document with the include directive is placed. 24 | 25 | Substrings of the form $name or ${name} are replaced by the value of 26 | environment variable name. Malformed variable names and references to 27 | non-existing variables are left unchanged. 28 | """ 29 | 30 | # ============================================================================== 31 | # imports 32 | # ============================================================================== 33 | 34 | import os.path 35 | 36 | from docutils import io, nodes, statemachine 37 | from docutils.utils.error_reporting import SafeString, ErrorString 38 | from docutils.parsers.rst import directives 39 | from docutils.parsers.rst.directives.body import CodeBlock, NumberLines 40 | from docutils.parsers.rst.directives.misc import Include 41 | 42 | __version__ = '1.0' 43 | 44 | # ============================================================================== 45 | def setup(app): 46 | # ============================================================================== 47 | 48 | app.add_directive("kernel-include", KernelInclude) 49 | return dict( 50 | version = __version__, 51 | parallel_read_safe = True, 52 | parallel_write_safe = True 53 | ) 54 | 55 | # ============================================================================== 56 | class KernelInclude(Include): 57 | # ============================================================================== 58 | 59 | u"""KernelInclude (``kernel-include``) directive""" 60 | 61 | def run(self): 62 | path = os.path.realpath( 63 | os.path.expandvars(self.arguments[0])) 64 | 65 | # to get a bit security back, prohibit /etc: 66 | if path.startswith(os.sep + "etc"): 67 | raise self.severe( 68 | 'Problems with "%s" directive, prohibited path: %s' 69 | % (self.name, path)) 70 | 71 | self.arguments[0] = path 72 | 73 | #return super(KernelInclude, self).run() # won't work, see HINTs in _run() 74 | return self._run() 75 | 76 | def _run(self): 77 | """Include a file as part of the content of this reST file.""" 78 | 79 | # HINT: I had to copy&paste the whole Include.run method. I'am not happy 80 | # with this, but due to security reasons, the Include.run method does 81 | # not allow absolute or relative pathnames pointing to locations *above* 82 | # the filesystem tree where the reST document is placed. 83 | 84 | if not self.state.document.settings.file_insertion_enabled: 85 | raise self.warning('"%s" directive disabled.' % self.name) 86 | source = self.state_machine.input_lines.source( 87 | self.lineno - self.state_machine.input_offset - 1) 88 | source_dir = os.path.dirname(os.path.abspath(source)) 89 | path = directives.path(self.arguments[0]) 90 | if path.startswith('<') and path.endswith('>'): 91 | path = os.path.join(self.standard_include_path, path[1:-1]) 92 | path = os.path.normpath(os.path.join(source_dir, path)) 93 | 94 | # HINT: this is the only line I had to change / commented out: 95 | #path = utils.relative_path(None, path) 96 | 97 | path = nodes.reprunicode(path) 98 | encoding = self.options.get( 99 | 'encoding', self.state.document.settings.input_encoding) 100 | e_handler=self.state.document.settings.input_encoding_error_handler 101 | tab_width = self.options.get( 102 | 'tab-width', self.state.document.settings.tab_width) 103 | try: 104 | self.state.document.settings.record_dependencies.add(path) 105 | include_file = io.FileInput(source_path=path, 106 | encoding=encoding, 107 | error_handler=e_handler) 108 | except UnicodeEncodeError as error: 109 | raise self.severe('Problems with "%s" directive path:\n' 110 | 'Cannot encode input file path "%s" ' 111 | '(wrong locale?).' % 112 | (self.name, SafeString(path))) 113 | except IOError as error: 114 | raise self.severe('Problems with "%s" directive path:\n%s.' % 115 | (self.name, ErrorString(error))) 116 | startline = self.options.get('start-line', None) 117 | endline = self.options.get('end-line', None) 118 | try: 119 | if startline or (endline is not None): 120 | lines = include_file.readlines() 121 | rawtext = ''.join(lines[startline:endline]) 122 | else: 123 | rawtext = include_file.read() 124 | except UnicodeError as error: 125 | raise self.severe('Problem with "%s" directive:\n%s' % 126 | (self.name, ErrorString(error))) 127 | # start-after/end-before: no restrictions on newlines in match-text, 128 | # and no restrictions on matching inside lines vs. line boundaries 129 | after_text = self.options.get('start-after', None) 130 | if after_text: 131 | # skip content in rawtext before *and incl.* a matching text 132 | after_index = rawtext.find(after_text) 133 | if after_index < 0: 134 | raise self.severe('Problem with "start-after" option of "%s" ' 135 | 'directive:\nText not found.' % self.name) 136 | rawtext = rawtext[after_index + len(after_text):] 137 | before_text = self.options.get('end-before', None) 138 | if before_text: 139 | # skip content in rawtext after *and incl.* a matching text 140 | before_index = rawtext.find(before_text) 141 | if before_index < 0: 142 | raise self.severe('Problem with "end-before" option of "%s" ' 143 | 'directive:\nText not found.' % self.name) 144 | rawtext = rawtext[:before_index] 145 | 146 | include_lines = statemachine.string2lines(rawtext, tab_width, 147 | convert_whitespace=True) 148 | if 'literal' in self.options: 149 | # Convert tabs to spaces, if `tab_width` is positive. 150 | if tab_width >= 0: 151 | text = rawtext.expandtabs(tab_width) 152 | else: 153 | text = rawtext 154 | literal_block = nodes.literal_block(rawtext, source=path, 155 | classes=self.options.get('class', [])) 156 | literal_block.line = 1 157 | self.add_name(literal_block) 158 | if 'number-lines' in self.options: 159 | try: 160 | startline = int(self.options['number-lines'] or 1) 161 | except ValueError: 162 | raise self.error(':number-lines: with non-integer ' 163 | 'start value') 164 | endline = startline + len(include_lines) 165 | if text.endswith('\n'): 166 | text = text[:-1] 167 | tokens = NumberLines([([], text)], startline, endline) 168 | for classes, value in tokens: 169 | if classes: 170 | literal_block += nodes.inline(value, value, 171 | classes=classes) 172 | else: 173 | literal_block += nodes.Text(value, value) 174 | else: 175 | literal_block += nodes.Text(text, text) 176 | return [literal_block] 177 | if 'code' in self.options: 178 | self.options['source'] = path 179 | codeblock = CodeBlock(self.name, 180 | [self.options.pop('code')], # arguments 181 | self.options, 182 | include_lines, # content 183 | self.lineno, 184 | self.content_offset, 185 | self.block_text, 186 | self.state, 187 | self.state_machine) 188 | return codeblock.run() 189 | self.state_machine.insert_input(include_lines, path) 190 | return [] 191 | -------------------------------------------------------------------------------- /doc/sphinx/kerneldoc.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # 3 | # Copyright © 2016 Intel Corporation 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a 6 | # copy of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom the 10 | # Software is furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice (including the next 13 | # paragraph) shall be included in all copies or substantial portions of the 14 | # Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | # IN THE SOFTWARE. 23 | # 24 | # Authors: 25 | # Jani Nikula 26 | # 27 | # Please make sure this works on both python2 and python3. 28 | # 29 | 30 | import codecs 31 | import os 32 | import subprocess 33 | import sys 34 | import re 35 | import glob 36 | 37 | from docutils import nodes, statemachine 38 | from docutils.statemachine import ViewList 39 | from docutils.parsers.rst import directives, Directive 40 | from sphinx.ext.autodoc import AutodocReporter 41 | 42 | __version__ = '1.0' 43 | 44 | class KernelDocDirective(Directive): 45 | """Extract kernel-doc comments from the specified file""" 46 | required_argument = 1 47 | optional_arguments = 4 48 | option_spec = { 49 | 'doc': directives.unchanged_required, 50 | 'functions': directives.unchanged, 51 | 'export': directives.unchanged, 52 | 'internal': directives.unchanged, 53 | } 54 | has_content = False 55 | 56 | def run(self): 57 | env = self.state.document.settings.env 58 | cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno'] 59 | 60 | filename = env.config.kerneldoc_srctree + '/' + self.arguments[0] 61 | export_file_patterns = [] 62 | 63 | # Tell sphinx of the dependency 64 | env.note_dependency(os.path.abspath(filename)) 65 | 66 | tab_width = self.options.get('tab-width', self.state.document.settings.tab_width) 67 | 68 | # FIXME: make this nicer and more robust against errors 69 | if 'export' in self.options: 70 | cmd += ['-export'] 71 | export_file_patterns = str(self.options.get('export')).split() 72 | elif 'internal' in self.options: 73 | cmd += ['-internal'] 74 | export_file_patterns = str(self.options.get('internal')).split() 75 | elif 'doc' in self.options: 76 | cmd += ['-function', str(self.options.get('doc'))] 77 | elif 'functions' in self.options: 78 | functions = self.options.get('functions').split() 79 | if functions: 80 | for f in functions: 81 | cmd += ['-function', f] 82 | else: 83 | cmd += ['-no-doc-sections'] 84 | 85 | for pattern in export_file_patterns: 86 | for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern): 87 | env.note_dependency(os.path.abspath(f)) 88 | cmd += ['-export-file', f] 89 | 90 | cmd += [filename] 91 | 92 | try: 93 | env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd))) 94 | 95 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 96 | out, err = p.communicate() 97 | 98 | out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') 99 | 100 | if p.returncode != 0: 101 | sys.stderr.write(err) 102 | 103 | env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode)) 104 | return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] 105 | elif env.config.kerneldoc_verbosity > 0: 106 | sys.stderr.write(err) 107 | 108 | lines = statemachine.string2lines(out, tab_width, convert_whitespace=True) 109 | result = ViewList() 110 | 111 | lineoffset = 0; 112 | line_regex = re.compile("^#define LINENO ([0-9]+)$") 113 | for line in lines: 114 | match = line_regex.search(line) 115 | if match: 116 | # sphinx counts lines from 0 117 | lineoffset = int(match.group(1)) - 1 118 | # we must eat our comments since the upset the markup 119 | else: 120 | result.append(line, filename, lineoffset) 121 | lineoffset += 1 122 | 123 | node = nodes.section() 124 | buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter 125 | self.state.memo.reporter = AutodocReporter(result, self.state.memo.reporter) 126 | self.state.memo.title_styles, self.state.memo.section_level = [], 0 127 | try: 128 | self.state.nested_parse(result, 0, node, match_titles=1) 129 | finally: 130 | self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf 131 | 132 | return node.children 133 | 134 | except Exception as e: # pylint: disable=W0703 135 | env.app.warn('kernel-doc \'%s\' processing failed with: %s' % 136 | (" ".join(cmd), str(e))) 137 | return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] 138 | 139 | def setup(app): 140 | app.add_config_value('kerneldoc_bin', None, 'env') 141 | app.add_config_value('kerneldoc_srctree', None, 'env') 142 | app.add_config_value('kerneldoc_verbosity', 1, 'env') 143 | 144 | app.add_directive('kernel-doc', KernelDocDirective) 145 | 146 | return dict( 147 | version = __version__, 148 | parallel_read_safe = True, 149 | parallel_write_safe = True 150 | ) 151 | -------------------------------------------------------------------------------- /doc/sphinx/load_config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8; mode: python -*- 2 | # pylint: disable=R0903, C0330, R0914, R0912, E0401 3 | 4 | import os 5 | import sys 6 | from sphinx.util.pycompat import execfile_ 7 | 8 | # ------------------------------------------------------------------------------ 9 | def loadConfig(namespace): 10 | # ------------------------------------------------------------------------------ 11 | 12 | u"""Load an additional configuration file into *namespace*. 13 | 14 | The name of the configuration file is taken from the environment 15 | ``SPHINX_CONF``. The external configuration file extends (or overwrites) the 16 | configuration values from the origin ``conf.py``. With this you are able to 17 | maintain *build themes*. """ 18 | 19 | config_file = os.environ.get("SPHINX_CONF", None) 20 | if (config_file is not None 21 | and os.path.normpath(namespace["__file__"]) != os.path.normpath(config_file) ): 22 | config_file = os.path.abspath(config_file) 23 | 24 | if os.path.isfile(config_file): 25 | sys.stdout.write("load additional sphinx-config: %s\n" % config_file) 26 | config = namespace.copy() 27 | config['__file__'] = config_file 28 | execfile_(config_file, config) 29 | del config['__file__'] 30 | namespace.update(config) 31 | else: 32 | sys.stderr.write("WARNING: additional sphinx-config not found: %s\n" % config_file) 33 | -------------------------------------------------------------------------------- /examples/Makefile.in: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Kernel module implementing a few simple examples of KTF tests 6 | # 7 | 8 | KVER = @KVER@ 9 | KTF_DIR = @KTF_DIR@ 10 | KTF_BDIR = @KTF_BDIR@ 11 | 12 | -include ktf_gen.mk 13 | 14 | ccflags-y += -I$(KTF_DIR) 15 | 16 | obj-m := hello.o h2.o h3.o h4.o 17 | 18 | ifdef CONFIG_KGDB 19 | obj-m += kgdemo.o 20 | endif 21 | 22 | KDIR := @KDIR@ 23 | PWD := $(shell pwd) 24 | 25 | EXTRASYMS := KBUILD_EXTRA_SYMBOLS="$(KTF_BDIR)/Module.symvers" 26 | 27 | module: 28 | $(MAKE) -C $(KDIR) M=$(PWD) $(EXTRASYMS) modules 29 | 30 | modules_install: 31 | $(MAKE) -C $(KDIR) M=$(PWD) $(EXTRASYMS) modules_install 32 | 33 | clean: 34 | $(MAKE) -C $(KDIR) M=$(PWD) clean 35 | 36 | check: all 37 | $(MAKE) -C $(KDIR) M=$(PWD) C=2 38 | -------------------------------------------------------------------------------- /examples/h2.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | */ 6 | 7 | #include 8 | #include "ktf.h" 9 | 10 | MODULE_LICENSE("GPL"); 11 | 12 | KTF_INIT(); 13 | 14 | #define MAX_CNT 3 15 | 16 | struct hello_ctx { 17 | struct ktf_context k; 18 | int value[MAX_CNT]; 19 | }; 20 | 21 | static struct hello_ctx myctx = { .value = { 0, 1, 4 } }; 22 | 23 | TEST(examples, cmp) 24 | { 25 | struct hello_ctx *hctx = KTF_CONTEXT_GET("value", struct hello_ctx); 26 | 27 | EXPECT_INT_EQ(_i, hctx->value[_i]); 28 | } 29 | 30 | static void add_tests(void) 31 | { 32 | ADD_LOOP_TEST(cmp, 0, MAX_CNT); 33 | } 34 | 35 | static int __init hello_init(void) 36 | { 37 | KTF_CONTEXT_ADD(&myctx.k, "value"); 38 | add_tests(); 39 | return 0; 40 | } 41 | 42 | static void __exit hello_exit(void) 43 | { 44 | struct ktf_context *kctx = KTF_CONTEXT_FIND("value"); 45 | 46 | KTF_CONTEXT_REMOVE(kctx); 47 | KTF_CLEANUP(); 48 | } 49 | 50 | module_init(hello_init); 51 | module_exit(hello_exit); 52 | -------------------------------------------------------------------------------- /examples/h3.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | */ 6 | 7 | #include 8 | #include "ktf.h" 9 | 10 | MODULE_LICENSE("GPL"); 11 | 12 | KTF_INIT(); 13 | 14 | DECLARE_F(hello_fixture) 15 | struct list_head head; 16 | }; 17 | 18 | struct my_element { 19 | struct list_head list; 20 | int value; 21 | }; 22 | 23 | SETUP_F(hello_fixture, hello_setup) 24 | { 25 | int i; 26 | 27 | INIT_LIST_HEAD(&hello_fixture->head); 28 | for (i = 0; i < 10; i++) { 29 | struct my_element *e = kzalloc(sizeof(*e), GFP_KERNEL); 30 | 31 | e->value = i; 32 | list_add_tail(&e->list, &hello_fixture->head); 33 | } 34 | hello_fixture->ok = true; 35 | } 36 | 37 | TEARDOWN_F(hello_fixture, hello_teardown) 38 | { 39 | struct list_head *p, *next_p; 40 | 41 | /* Just cleanup whatever is left after the test */ 42 | list_for_each_safe(p, next_p, &hello_fixture->head) { 43 | struct my_element *e = list_entry(p, struct my_element, list); 44 | 45 | list_del(&e->list); 46 | kfree(e); 47 | } 48 | EXPECT_TRUE(list_empty(&hello_fixture->head)); 49 | } 50 | 51 | INIT_F(hello_fixture, hello_setup, hello_teardown); 52 | 53 | TEST_F(hello_fixture, examples, hello_del) 54 | { 55 | int cnt = 0; 56 | int cnt_ones = 0; 57 | struct my_element *e = kzalloc(sizeof(*e), GFP_KERNEL); 58 | 59 | e->value = 1; 60 | list_add(&e->list, &ctx->head); 61 | 62 | list_for_each_entry(e, &ctx->head, list) { 63 | if (e->value == 1) 64 | cnt_ones++; 65 | cnt++; 66 | } 67 | EXPECT_INT_EQ(11, cnt); 68 | EXPECT_INT_EQ(2, cnt_ones); 69 | } 70 | 71 | static void add_tests(void) 72 | { 73 | ADD_TEST(hello_del); 74 | } 75 | 76 | static int __init hello_init(void) 77 | { 78 | add_tests(); 79 | tlog(T_INFO, "hello: loaded"); 80 | return 0; 81 | } 82 | 83 | static void __exit hello_exit(void) 84 | { 85 | KTF_CLEANUP(); 86 | tlog(T_INFO, "hello: unloaded"); 87 | } 88 | 89 | module_init(hello_init); 90 | module_exit(hello_exit); 91 | -------------------------------------------------------------------------------- /examples/h4.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | */ 6 | 7 | #include 8 | #include "ktf.h" 9 | 10 | MODULE_LICENSE("GPL"); 11 | 12 | KTF_INIT(); 13 | 14 | static int count; 15 | static int ret; 16 | 17 | KTF_ENTRY_PROBE(printk, printkhandler) 18 | { 19 | count++; 20 | 21 | KTF_ENTRY_PROBE_RETURN(0); 22 | } 23 | 24 | TEST(examples, entrycheck) 25 | { 26 | count = 0; 27 | ASSERT_INT_EQ_GOTO(KTF_REGISTER_ENTRY_PROBE(printk, printkhandler), 28 | 0, done); 29 | printk(KERN_INFO "Testing kprobe entry..."); 30 | ASSERT_INT_GT_GOTO(count, 0, done); 31 | done: 32 | KTF_UNREGISTER_ENTRY_PROBE(printk, printkhandler); 33 | } 34 | 35 | KTF_RETURN_PROBE(printk, printkrethandler) 36 | { 37 | ret = KTF_RETURN_VALUE(); 38 | 39 | return 0; 40 | } 41 | 42 | TEST(examples, returncheck) 43 | { 44 | char *teststr = "Testing kprobe return..."; 45 | 46 | ret = -1; 47 | ASSERT_INT_EQ_GOTO(KTF_REGISTER_RETURN_PROBE(printk, printkrethandler), 48 | 0, done); 49 | printk(KERN_INFO "%s", teststr); 50 | ASSERT_INT_EQ_GOTO(ret, strlen(teststr), done); 51 | done: 52 | KTF_UNREGISTER_RETURN_PROBE(printk, printkrethandler); 53 | } 54 | 55 | static int __init hello_init(void) 56 | { 57 | ADD_TEST(entrycheck); 58 | ADD_TEST(returncheck); 59 | return 0; 60 | } 61 | 62 | static void __exit hello_exit(void) 63 | { 64 | KTF_CLEANUP(); 65 | } 66 | 67 | module_init(hello_init); 68 | module_exit(hello_exit); 69 | -------------------------------------------------------------------------------- /examples/hello.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | */ 6 | 7 | #include 8 | #include "ktf.h" 9 | 10 | MODULE_LICENSE("GPL"); 11 | 12 | KTF_INIT(); 13 | 14 | TEST(examples, hello_ok) 15 | { 16 | EXPECT_TRUE(true); 17 | } 18 | 19 | TEST(examples, hello_fail) 20 | { 21 | EXPECT_TRUE(false); 22 | } 23 | 24 | static void add_tests(void) 25 | { 26 | ADD_TEST(hello_ok); 27 | ADD_TEST(hello_fail); 28 | } 29 | 30 | static int __init hello_init(void) 31 | { 32 | add_tests(); 33 | tlog(T_INFO, "hello: loaded"); 34 | return 0; 35 | } 36 | 37 | static void __exit hello_exit(void) 38 | { 39 | KTF_CLEANUP(); 40 | tlog(T_INFO, "hello: unloaded"); 41 | } 42 | 43 | module_init(hello_init); 44 | module_exit(hello_exit); 45 | -------------------------------------------------------------------------------- /examples/kgdemo.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | */ 6 | 7 | #include 8 | #include "ktf.h" 9 | 10 | /* 11 | * A trivial and somewhat rough example used by the author 12 | * for pedagogical purposes, to demonstrate 13 | * interactive debugging with kgdb. 14 | * 15 | * Requires a kernel built with CONFIG_KGDB 16 | * 17 | * Note: these test breaks into kgdb and/or creates a NULL 18 | * pointer exception and corresponding stack dump, so 19 | * try out in a test environment only! 20 | */ 21 | 22 | MODULE_LICENSE("GPL"); 23 | 24 | KTF_INIT(); 25 | 26 | #define MAX_CNT 3 27 | #include 28 | 29 | static int kgdemo_cnt; 30 | static int *bogus_ref; 31 | 32 | TEST(kgdb, breakpoint) 33 | { 34 | kgdemo_cnt = 0; 35 | printk(KERN_INFO "** Please set kgdemo_cnt = 1 **\n"); 36 | kgdb_breakpoint(); 37 | EXPECT_INT_EQ(1, kgdemo_cnt); 38 | } 39 | 40 | TEST(kgdb, nullpointer) 41 | { 42 | int pre = kgdemo_cnt; 43 | 44 | int b = *bogus_ref++; 45 | 46 | EXPECT_INT_EQ(pre + 1, b); 47 | } 48 | 49 | static void add_tests(void) 50 | { 51 | ADD_TEST(breakpoint); 52 | ADD_TEST(nullpointer); 53 | } 54 | 55 | static int __init kgdemo_init(void) 56 | { 57 | add_tests(); 58 | return 0; 59 | } 60 | 61 | static void __exit kgdemo_exit(void) 62 | { 63 | KTF_CLEANUP(); 64 | } 65 | 66 | module_init(kgdemo_init); 67 | module_exit(kgdemo_exit); 68 | -------------------------------------------------------------------------------- /examples/runchecks.cfg: -------------------------------------------------------------------------------- 1 | 2 | checker checkpatch 3 | 4 | # Older kernels fail on the SPDX license tag which now uses //: 5 | pervasive C99_COMMENTS 6 | 7 | # The use of printk here is part of the purpose of the examples: 8 | except PREFER_PR_LEVEL h4.c kgdemo.c 9 | 10 | checker sparse 11 | 12 | # No good way to resolve all these without adding burden to test writers: 13 | pervasive DECL 14 | 15 | # sparse produce errors for this from slab.h in 4.20: 16 | except DUBIOUS_EXPR h3.c 17 | -------------------------------------------------------------------------------- /kernel/.gitignore: -------------------------------------------------------------------------------- 1 | .tmp_versions/ 2 | Module.symvers 3 | modules.order 4 | sif_test.ko 5 | sif_test.mod.c 6 | -------------------------------------------------------------------------------- /kernel/Makefile.in: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Implementation of the kernel part of Kernel Test Framework (KTF), 6 | # a framework for running unit test like tests within the kernel. 7 | # 8 | 9 | KVER = @KVER@ 10 | 11 | obj-m := ktf.o 12 | 13 | -include ktf_gen.mk 14 | 15 | ktf-y := ktf_context.o ktf_nl.o ktf_map.o ktf_test.o ktf_debugfs.o ktf_cov.o \ 16 | ktf_override.o ktf_netctx.o ktf_kallsyms.o 17 | 18 | KDIR := @KDIR@ 19 | PWD := $(shell pwd) 20 | 21 | module: 22 | $(MAKE) -C $(KDIR) M=$(PWD) 23 | 24 | modules_install: 25 | $(MAKE) -C $(KDIR) M=$(PWD) modules_install 26 | 27 | clean: 28 | $(MAKE) -C $(KDIR) M=$(PWD) clean 29 | 30 | check: all 31 | $(MAKE) -C $(KDIR) M=$(PWD) C=2 32 | -------------------------------------------------------------------------------- /kernel/ktf_compat.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf_compat.h: Backward compatibility support 7 | */ 8 | 9 | /* 10 | * At any time we want to keep KTF code and users 11 | * as closely as possible compatible with the latest kernel APIs. 12 | * This file allows the main code paths to be clean of ifdefs 13 | * while still allowing KTF and new and old tests to be compatible 14 | * with older kernel versions. 15 | 16 | * Please add wrapper macros and functions 17 | * here as needed to keep old versions compiling while 18 | * making the code compile with newer kernels: 19 | */ 20 | 21 | #ifndef _KTF_COMPAT_H 22 | #define _KTF_COMPAT_H 23 | 24 | #if (KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE) 25 | #define refcount_read atomic_read 26 | #endif 27 | 28 | #if (KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE) 29 | #define nla_put_u64_64bit(m, c, v, x) nla_put_u64(m, c, v) 30 | #endif 31 | 32 | #if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE) 33 | static inline void *nla_memdup(const struct nlattr *src, gfp_t gfp) 34 | { 35 | return kmemdup(nla_data(src), nla_len(src), gfp); 36 | } 37 | #endif 38 | 39 | #if (KERNEL_VERSION(5, 2, 0) > LINUX_VERSION_CODE) 40 | static inline unsigned int stack_trace_save(unsigned long *store, unsigned int size, 41 | unsigned int skipnr) 42 | { 43 | struct stack_trace trace; 44 | 45 | trace.nr_entries = 0; 46 | trace.entries = store; 47 | trace.max_entries = size; 48 | trace.skip = skipnr; 49 | save_stack_trace(&trace); 50 | return trace.nr_entries; 51 | } 52 | #endif 53 | 54 | #if (KERNEL_VERSION(5, 11, 0) > LINUX_VERSION_CODE) 55 | #define nla_strscpy nla_strlcpy 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /kernel/ktf_cov.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Alan Maguire 5 | * 6 | * ktf_cov.h: Code coverage support interface for KTF. 7 | */ 8 | 9 | #ifndef KTF_COV_H 10 | #define KTF_COV_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include "ktf.h" 16 | #include "ktf_map.h" 17 | 18 | enum ktf_cov_type { 19 | KTF_COV_TYPE_MODULE, 20 | KTF_COV_TYPE_MAX, 21 | }; 22 | 23 | struct ktf_cov { 24 | struct ktf_map_elem kmap; 25 | enum ktf_cov_type type; /* only modules supported for now. */ 26 | int count; /* number of unique functions called */ 27 | int total; /* total number of functions */ 28 | unsigned int opts; 29 | }; 30 | 31 | /* Key for coverage entries (functions) consists in function address _and_ 32 | * size - this allows us to find offsets in function on stack. Also used 33 | * to track allocated memory - allocated address + size. 34 | */ 35 | struct ktf_cov_obj_key { 36 | unsigned long address; 37 | unsigned long size; 38 | }; 39 | 40 | #define KTF_COV_ENTRY_MAGIC 0xc07e8a5e 41 | struct ktf_cov_entry { 42 | struct kprobe kprobe; 43 | int magic; /* magic number identifying entry */ 44 | struct ktf_map_elem kmap; 45 | char name[KTF_MAX_KEY]; 46 | struct ktf_cov_obj_key key; 47 | struct ktf_cov *cov; 48 | struct ktf_map cov_mem; 49 | int refcnt; 50 | int count; 51 | }; 52 | 53 | #define KTF_COV_MAX_STACK_DEPTH 32 54 | 55 | struct ktf_cov_mem { 56 | struct ktf_map_elem kmap; 57 | struct ktf_cov_obj_key key; 58 | unsigned long flags; 59 | unsigned int nr_entries; 60 | unsigned long stack_entries[KTF_COV_MAX_STACK_DEPTH]; 61 | }; 62 | 63 | #define KTF_COV_MEM_IGNORE 0x1 /* avoid recursive enter */ 64 | 65 | struct ktf_cov_mem_probe { 66 | const char *name; 67 | struct kretprobe kretprobe; 68 | }; 69 | 70 | extern struct ktf_map cov_mem_map; 71 | 72 | #define ktf_for_each_cov_mem(pos) \ 73 | ktf_map_for_each_entry(pos, &cov_mem_map, kmap) 74 | 75 | struct ktf_cov_entry *ktf_cov_entry_find(unsigned long, unsigned long); 76 | void ktf_cov_entry_put(struct ktf_cov_entry *); 77 | void ktf_cov_entry_get(struct ktf_cov_entry *); 78 | 79 | struct ktf_cov *ktf_cov_find(const char *); 80 | void ktf_cov_put(struct ktf_cov *); 81 | void ktf_cov_get(struct ktf_cov *); 82 | 83 | struct ktf_cov_mem *ktf_cov_mem_find(unsigned long, unsigned long); 84 | void ktf_cov_mem_put(struct ktf_cov_mem *); 85 | void ktf_cov_mem_get(struct ktf_cov_mem *); 86 | 87 | void ktf_cov_seq_print(struct seq_file *); 88 | void ktf_cov_cleanup(void); 89 | 90 | int ktf_cov_enable(const char *, unsigned int); 91 | void ktf_cov_disable(const char *); 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /kernel/ktf_debugfs.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Alan Maguire 5 | * 6 | * ktf_debugfs.h: Support for creating a debugfs representation of test 7 | * sets/tests. 8 | */ 9 | 10 | #ifndef KTF_DEBUGFS_H 11 | #define KTF_DEBUGFS_H 12 | #include 13 | 14 | #define KTF_DEBUGFS_ROOT "ktf" 15 | #define KTF_DEBUGFS_RUN "run" 16 | #define KTF_DEBUGFS_RESULTS "results" 17 | #define KTF_DEBUGFS_COV "coverage" 18 | #define KTF_DEBUGFS_TESTS_SUFFIX "-tests" 19 | 20 | #define KTF_DEBUGFS_NAMESZ 256 21 | 22 | struct ktf_test; 23 | struct ktf_case; 24 | 25 | void ktf_debugfs_create_test(struct ktf_test *); 26 | void ktf_debugfs_destroy_test(struct ktf_test *); 27 | void ktf_debugfs_create_testset(struct ktf_case *); 28 | void ktf_debugfs_destroy_testset(struct ktf_case *); 29 | void ktf_debugfs_init(void); 30 | void ktf_debugfs_cleanup(void); 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /kernel/ktf_kallsyms.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2021 Knut Omang 4 | * 5 | * ktf_kallsyms.c: Access to kernel private symbols for bootstrapping 6 | * 7 | * With workaround to bootstrap access to kallsyms_lookup_name itself 8 | * after it was made inaccessible to modules in 9 | * commit 'kallsyms: unexport kallsyms_lookup_name() and kallsyms_on_each_symbol()' 10 | * Inspired by https://github.com/zizzu0/LinuxKernelModules 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "ktf.h" 18 | #include "ktf_kallsyms.h" 19 | 20 | struct ktf_kernel_internals ki; 21 | 22 | #if (KERNEL_VERSION(5, 8, 0) <= LINUX_VERSION_CODE) 23 | 24 | static off_t ktf_kallsyms_offset = 0; 25 | static unsigned long kallsyms_lookup_name_probe_entry = 0; 26 | 27 | KTF_ENTRY_PROBE(kallsyms_lookup_name, aln_init) 28 | { 29 | kallsyms_lookup_name_probe_entry = instruction_pointer(regs); 30 | KTF_ENTRY_PROBE_RETURN(0); 31 | } 32 | 33 | KTF_ENTRY_PROBE(kfree, verif) 34 | { 35 | ktf_kallsyms_offset = (off_t)instruction_pointer(regs) - (off_t)kfree; 36 | KTF_ENTRY_PROBE_RETURN(0); 37 | } 38 | 39 | int ktf_kallsyms_bootstrap(void) 40 | { 41 | /* Register a probe on kallsyms_lookup_name to get the address where the probe entered: */ 42 | int stat = KTF_REGISTER_ENTRY_PROBE(kallsyms_lookup_name, aln_init); 43 | if (stat) 44 | goto init_failed; 45 | 46 | /* Determine the offset from the function the probe is on to the 47 | * instruction pointer when we enter the probe by using a probe on a 48 | * known symbol: kfree() can be safely called with 0 without side effects 49 | * and is unlikely to change definition in a future kernel. 50 | * 51 | * By registering a second probe we also implicitly trigger a call to the first 52 | * probe since kallsym_lookup_name is used internally to find the address of 53 | * the function to probe, here kfree: 54 | */ 55 | stat = KTF_REGISTER_ENTRY_PROBE(kfree, verif); 56 | if (stat) { 57 | KTF_UNREGISTER_ENTRY_PROBE(kallsyms_lookup_name, aln_init); 58 | goto init_failed; 59 | } 60 | 61 | /* Now make sure kfree() has been called at least once with the probe: 62 | * (it likely has been called several times already but that's no big deal) 63 | */ 64 | kfree(0); 65 | KTF_UNREGISTER_ENTRY_PROBE(kfree, verif); 66 | KTF_UNREGISTER_ENTRY_PROBE(kallsyms_lookup_name, aln_init); 67 | 68 | ki.kallsyms_lookup_name = (void*)(kallsyms_lookup_name_probe_entry - ktf_kallsyms_offset); 69 | if (ki.kallsyms_lookup_name) { 70 | tlog(T_DEBUG, "Got kallsyms_lookup_name at %p", ki.kallsyms_lookup_name); 71 | } else { 72 | terr("Unable to access the address of 'kallsyms_lookup_name'"); 73 | return -ENODEV; 74 | } 75 | return 0; 76 | init_failed: 77 | terr("Failed to set up kallsyms access"); 78 | return stat; 79 | } 80 | #endif 81 | 82 | /* Support for looking up kernel/module internal symbols to enable testing. 83 | * A NULL mod means either we want the kernel-internal symbol or don't care 84 | * which module the symbol is in. 85 | */ 86 | void *ktf_find_symbol(const char *mod, const char *sym) 87 | { 88 | char sm[200]; 89 | const char *symref; 90 | unsigned long addr = 0; 91 | 92 | if (mod) { 93 | sprintf(sm, "%s:%s", mod, sym); 94 | symref = sm; 95 | } else { 96 | /* Try for kernel-internal symbol first; fall back to modules 97 | * if that fails. 98 | */ 99 | symref = sym; 100 | addr = ki.kallsyms_lookup_name(symref); 101 | } 102 | if (!addr) 103 | addr = ki.module_kallsyms_lookup_name(symref); 104 | if (addr) { 105 | tlog(T_DEBUG, "Found %s at %0lx", sym, addr); 106 | } else { 107 | #ifndef CONFIG_KALLSYMS_ALL 108 | twarn("CONFIG_KALLSYMS_ALL is not set, so non-exported symbols are not available"); 109 | #endif 110 | tlog(T_INFO, "Fatal error: %s not found", sym); 111 | return NULL; 112 | } 113 | return (void *)addr; 114 | } 115 | EXPORT_SYMBOL(ktf_find_symbol); 116 | 117 | unsigned long ktf_symbol_size(unsigned long addr) 118 | { 119 | unsigned long size = 0; 120 | 121 | (void)ki.kallsyms_lookup_size_offset(addr, &size, NULL); 122 | 123 | return size; 124 | } 125 | EXPORT_SYMBOL(ktf_symbol_size); 126 | 127 | int ktf_kallsyms_init(void) 128 | { 129 | char *ks; 130 | #if (KERNEL_VERSION(5, 8, 0) < LINUX_VERSION_CODE) 131 | int stat = ktf_kallsyms_bootstrap(); 132 | 133 | if (stat) 134 | return stat; 135 | #else 136 | ki.kallsyms_lookup_name = kallsyms_lookup_name; 137 | ki.kallsyms_on_each_symbol = kallsyms_on_each_symbol; 138 | #endif 139 | /* We rely on being able to resolve this symbol for looking up module 140 | * specific internal symbols (multiple modules may define the same symbol): 141 | */ 142 | ks = "module_kallsyms_lookup_name"; 143 | ki.module_kallsyms_lookup_name = (void *)ki.kallsyms_lookup_name(ks); 144 | if (!ki.module_kallsyms_lookup_name) { 145 | terr("Unable to look up \"%s\" in kallsyms - maybe interface has changed?", 146 | ks); 147 | return -EINVAL; 148 | } 149 | ks = "kallsyms_on_each_symbol"; 150 | ki.kallsyms_on_each_symbol = (void *)ki.kallsyms_lookup_name(ks); 151 | if (!ki.kallsyms_on_each_symbol) { 152 | terr("Unable to look up \"%s\" in kallsyms - maybe interface has changed?", 153 | ks); 154 | return -EINVAL; 155 | } 156 | ks = "kallsyms_lookup_size_offset"; 157 | ki.kallsyms_lookup_size_offset = (void *)ki.kallsyms_lookup_name(ks); 158 | if (!ki.kallsyms_lookup_size_offset) { 159 | terr("Unable to look up \"%s\" in kallsyms - maybe interface has changed?", 160 | ks); 161 | return -EINVAL; 162 | } 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /kernel/ktf_kallsyms.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2021 Knut Omang 4 | * 5 | * ktf_kallsyms.h: Access to kernel private symbols 6 | */ 7 | 8 | #ifndef _KTF_KALLSYMS_H 9 | #define _KTF_KALLSYMS_H 10 | #include 11 | 12 | int ktf_kallsyms_init(void); 13 | 14 | struct ktf_kernel_internals { 15 | /* From kallsyms.h: In kernels beyond 5.8 these are not exported to modules */ 16 | unsigned long (*kallsyms_lookup_name)(const char *name); 17 | int (*kallsyms_on_each_symbol)(int (*fn)(void *, const char *, struct module *, 18 | unsigned long), 19 | void *data); 20 | /* From module.h: Look up a module symbol - supports syntax module:name */ 21 | unsigned long (*module_kallsyms_lookup_name)(const char *name); 22 | /* From kallsyms.h: Look up a symbol w/size and offset */ 23 | unsigned long (*kallsyms_lookup_size_offset)(unsigned long addr, 24 | unsigned long *symbolsize, 25 | unsigned long *offset); 26 | }; 27 | 28 | extern struct ktf_kernel_internals ki; 29 | #endif 30 | -------------------------------------------------------------------------------- /kernel/ktf_map.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf_map.c: Implementation of a kernel version independent std::map like API 7 | * (made abstract to allow impl to change) 8 | */ 9 | 10 | #include "ktf_map.h" 11 | #include "ktf.h" 12 | #include "ktf_compat.h" 13 | 14 | void ktf_map_init(struct ktf_map *map, ktf_map_elem_comparefn elem_comparefn, 15 | ktf_map_elem_freefn elem_freefn) 16 | { 17 | map->root = RB_ROOT; 18 | map->size = 0; 19 | map->elem_comparefn = elem_comparefn; 20 | map->elem_freefn = elem_freefn; 21 | spin_lock_init(&map->lock); 22 | } 23 | 24 | int ktf_map_elem_init(struct ktf_map_elem *elem, const char *key) 25 | { 26 | memcpy(elem->key, key, KTF_MAX_KEY); 27 | /* For strings that are too long, ensure truncation at 28 | * KTF_MAX_NAME == KTF_MAX_KEY - 1 length: 29 | */ 30 | elem->key[KTF_MAX_NAME] = '\0'; 31 | elem->map = NULL; 32 | kref_init(&elem->refcount); 33 | return 0; 34 | } 35 | 36 | /* A convenience unsigned int compare function as an alternative 37 | * to the string compare: 38 | */ 39 | int ktf_uint_compare(const char *ac, const char *bc) 40 | { 41 | unsigned int a = *((unsigned int *)ac); 42 | unsigned int b = *((unsigned int *)bc); 43 | 44 | return a > b ? 1 : (a < b ? -1 : 0); 45 | } 46 | EXPORT_SYMBOL(ktf_uint_compare); 47 | 48 | /* Copy "elem"s key representation into "name". For cases where no 49 | * compare function is defined - i.e. string keys - just copy string, 50 | * otherwise name is hexascii of first 8 bytes of key. 51 | */ 52 | char * 53 | ktf_map_elem_name(struct ktf_map_elem *elem, char *name) 54 | { 55 | if (!name) 56 | return NULL; 57 | 58 | if (!elem || !elem->map) 59 | (void)strscpy(name, "", KTF_MAX_NAME); 60 | else if (!elem->map->elem_comparefn) 61 | (void)strscpy(name, elem->key, KTF_MAX_NAME); 62 | else 63 | (void)snprintf(name, KTF_MAX_NAME, "'%*ph'", 8, elem->key); 64 | 65 | return name; 66 | } 67 | 68 | /* Called when refcount of elem is 0. */ 69 | static void ktf_map_elem_release(struct kref *kref) 70 | { 71 | struct ktf_map_elem *elem = container_of(kref, struct ktf_map_elem, 72 | refcount); 73 | struct ktf_map *map = elem->map; 74 | char name[KTF_MAX_KEY]; 75 | 76 | tlog(T_DEBUG_V, "Releasing %s, %s free function", 77 | ktf_map_elem_name(elem, name), 78 | map && map->elem_freefn ? "calling" : "no"); 79 | if (map && map->elem_freefn) 80 | map->elem_freefn(elem); 81 | } 82 | 83 | void ktf_map_elem_put(struct ktf_map_elem *elem) 84 | { 85 | char name[KTF_MAX_KEY]; 86 | 87 | tlog(T_DEBUG_V, "Decreasing refcount for %s to %d", 88 | ktf_map_elem_name(elem, name), 89 | refcount_read(&elem->refcount.refcount) - 1); 90 | kref_put(&elem->refcount, ktf_map_elem_release); 91 | } 92 | 93 | void ktf_map_elem_get(struct ktf_map_elem *elem) 94 | { 95 | char name[KTF_MAX_KEY]; 96 | 97 | tlog(T_DEBUG_V, "Increasing refcount for %s to %d", 98 | ktf_map_elem_name(elem, name), 99 | refcount_read(&elem->refcount.refcount) + 1); 100 | kref_get(&elem->refcount); 101 | } 102 | 103 | struct ktf_map_elem *ktf_map_find(struct ktf_map *map, const char *key) 104 | { 105 | struct rb_node *node; 106 | unsigned long flags; 107 | 108 | /* may be called in interrupt context */ 109 | spin_lock_irqsave(&map->lock, flags); 110 | node = map->root.rb_node; 111 | 112 | while (node) { 113 | struct ktf_map_elem *elem = container_of(node, struct ktf_map_elem, node); 114 | int result; 115 | 116 | if (map->elem_comparefn) 117 | result = map->elem_comparefn(key, elem->key); 118 | else 119 | result = strncmp(key, elem->key, KTF_MAX_KEY); 120 | 121 | if (result < 0) { 122 | node = node->rb_left; 123 | } else if (result > 0) { 124 | node = node->rb_right; 125 | } else { 126 | ktf_map_elem_get(elem); 127 | spin_unlock_irqrestore(&map->lock, flags); 128 | return elem; 129 | } 130 | } 131 | spin_unlock_irqrestore(&map->lock, flags); 132 | return NULL; 133 | } 134 | 135 | /* Find the first map elem in 'map' */ 136 | struct ktf_map_elem *ktf_map_find_first(struct ktf_map *map) 137 | { 138 | struct ktf_map_elem *elem = NULL; 139 | struct rb_node *node; 140 | unsigned long flags; 141 | 142 | spin_lock_irqsave(&map->lock, flags); 143 | node = rb_first(&map->root); 144 | if (node) { 145 | elem = container_of(node, struct ktf_map_elem, node); 146 | ktf_map_elem_get(elem); 147 | } 148 | spin_unlock_irqrestore(&map->lock, flags); 149 | return elem; 150 | } 151 | 152 | /* Find the next element in the map after 'elem' if any */ 153 | struct ktf_map_elem *ktf_map_find_next(struct ktf_map_elem *elem) 154 | { 155 | struct ktf_map_elem *next = NULL; 156 | struct ktf_map *map = elem->map; 157 | struct rb_node *node; 158 | unsigned long flags; 159 | 160 | if (!elem->map) 161 | return NULL; 162 | spin_lock_irqsave(&map->lock, flags); 163 | node = rb_next(&elem->node); 164 | 165 | /* Assumption here - we don't need ref to elem any more. 166 | * Common usage pattern is 167 | * 168 | * for (elem = ktf_map_elem_first(map); elem != NULL; 169 | * elem = ktf_map_find_next(elem)) 170 | * 171 | * but if other use cases occur we may need to revisit. 172 | * This assumption allows us to define our _for_each macros 173 | * and still manage refcounts. 174 | */ 175 | ktf_map_elem_put(elem); 176 | 177 | if (node) { 178 | next = container_of(node, struct ktf_map_elem, node); 179 | ktf_map_elem_get(next); 180 | } 181 | spin_unlock_irqrestore(&map->lock, flags); 182 | return next; 183 | } 184 | 185 | int ktf_map_insert(struct ktf_map *map, struct ktf_map_elem *elem) 186 | { 187 | struct rb_node **newobj, *parent = NULL; 188 | unsigned long flags; 189 | 190 | spin_lock_irqsave(&map->lock, flags); 191 | newobj = &map->root.rb_node; 192 | while (*newobj) { 193 | struct ktf_map_elem *this = container_of(*newobj, struct ktf_map_elem, node); 194 | int result; 195 | 196 | if (map->elem_comparefn) 197 | result = map->elem_comparefn(elem->key, this->key); 198 | else 199 | result = strncmp(elem->key, this->key, KTF_MAX_KEY); 200 | 201 | parent = *newobj; 202 | if (result < 0) { 203 | newobj = &((*newobj)->rb_left); 204 | } else if (result > 0) { 205 | newobj = &((*newobj)->rb_right); 206 | } else { 207 | spin_unlock_irqrestore(&map->lock, flags); 208 | return -EEXIST; 209 | } 210 | } 211 | 212 | /* Add newobj node and rebalance tree. */ 213 | rb_link_node(&elem->node, parent, newobj); 214 | rb_insert_color(&elem->node, &map->root); 215 | elem->map = map; 216 | map->size++; 217 | /* Bump reference count for map reference */ 218 | ktf_map_elem_get(elem); 219 | spin_unlock_irqrestore(&map->lock, flags); 220 | return 0; 221 | } 222 | 223 | void ktf_map_remove_elem(struct ktf_map *map, struct ktf_map_elem *elem) 224 | { 225 | if (elem) { 226 | rb_erase(&elem->node, &map->root); 227 | map->size--; 228 | ktf_map_elem_put(elem); 229 | } 230 | } 231 | 232 | struct ktf_map_elem *ktf_map_remove(struct ktf_map *map, const char *key) 233 | { 234 | struct ktf_map_elem *elem; 235 | unsigned long flags; 236 | 237 | elem = ktf_map_find(map, key); 238 | spin_lock_irqsave(&map->lock, flags); 239 | ktf_map_remove_elem(map, elem); 240 | spin_unlock_irqrestore(&map->lock, flags); 241 | return elem; 242 | } 243 | 244 | void ktf_map_delete_all(struct ktf_map *map) 245 | { 246 | struct ktf_map_elem *elem; 247 | struct rb_node *node; 248 | unsigned long flags; 249 | 250 | spin_lock_irqsave(&map->lock, flags); 251 | do { 252 | node = rb_first(&(map)->root); 253 | if (node) { 254 | rb_erase(node, &(map)->root); 255 | map->size--; 256 | elem = container_of(node, struct ktf_map_elem, node); 257 | ktf_map_elem_put(elem); 258 | } 259 | } while (node); 260 | spin_unlock_irqrestore(&map->lock, flags); 261 | } 262 | -------------------------------------------------------------------------------- /kernel/ktf_map.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf_map.h: simple objects with key lookup to be inlined into a 7 | * larger object 8 | */ 9 | 10 | #ifndef _KTF_MAP_H 11 | #define _KTF_MAP_H 12 | #include 13 | #include 14 | #include 15 | 16 | #define KTF_MAX_KEY 64 17 | #define KTF_MAX_NAME (KTF_MAX_KEY - 1) 18 | 19 | struct ktf_map_elem; 20 | 21 | /* Compare function called to compare element keys - optional and if 22 | * not specified we revert to string comparison. Should return < 0 23 | * if first key < second, > 0 if first key > second, and 0 if they are 24 | * identical. 25 | */ 26 | typedef int (*ktf_map_elem_comparefn)(const char *, const char *); 27 | 28 | /* A convenience unsigned int compare function as an alternative 29 | * to the string compare: 30 | */ 31 | int ktf_uint_compare(const char *a, const char *b); 32 | 33 | /* Free function called when elem refcnt is 0 - optional and of course for 34 | * dynamically-allocated elems only. 35 | */ 36 | typedef void (*ktf_map_elem_freefn)(struct ktf_map_elem *); 37 | 38 | struct ktf_map { 39 | struct rb_root root; /* The rb tree holding the map */ 40 | size_t size; /* Current size (number of elements) of the map */ 41 | spinlock_t lock; /* held for map lookup etc */ 42 | ktf_map_elem_comparefn elem_comparefn; /* Key comparison function */ 43 | ktf_map_elem_freefn elem_freefn; /* Free function */ 44 | }; 45 | 46 | struct ktf_map_elem { 47 | struct rb_node node; /* Linkage for the map */ 48 | char key[KTF_MAX_KEY+1] __aligned(8); 49 | /* Key of the element - must be unique within the same map */ 50 | struct ktf_map *map; /* owning map */ 51 | struct kref refcount; /* reference count for element */ 52 | }; 53 | 54 | #define __KTF_MAP_INITIALIZER(_mapname, _elem_comparefn, _elem_freefn) \ 55 | { \ 56 | .root = RB_ROOT, \ 57 | .size = 0, \ 58 | .lock = __SPIN_LOCK_UNLOCKED(_mapname), \ 59 | .elem_comparefn = _elem_comparefn, \ 60 | .elem_freefn = _elem_freefn, \ 61 | } 62 | 63 | #define DEFINE_KTF_MAP(_mapname, _elem_comparefn, _elem_freefn) \ 64 | struct ktf_map _mapname = __KTF_MAP_INITIALIZER(_mapname, _elem_comparefn, _elem_freefn) 65 | 66 | void ktf_map_init(struct ktf_map *map, ktf_map_elem_comparefn elem_comparefn, 67 | ktf_map_elem_freefn elem_freefn); 68 | 69 | /* returns 0 upon success or -errno upon error */ 70 | int ktf_map_elem_init(struct ktf_map_elem *elem, const char *key); 71 | 72 | /* increase/reduce reference count to element. If count reaches 0, the 73 | * free function associated with map (if any) is called. 74 | */ 75 | void ktf_map_elem_get(struct ktf_map_elem *elem); 76 | void ktf_map_elem_put(struct ktf_map_elem *elem); 77 | 78 | char *ktf_map_elem_name(struct ktf_map_elem *elem, char *name); 79 | 80 | /* Insert a new element in map - return 0 iff 'elem' was inserted or -1 if 81 | * the key already existed - duplicates are not insterted. 82 | */ 83 | int ktf_map_insert(struct ktf_map *map, struct ktf_map_elem *elem); 84 | 85 | /* Find and return the element with 'key' */ 86 | struct ktf_map_elem *ktf_map_find(struct ktf_map *map, const char *key); 87 | 88 | /* Find the first map elem in 'map' with reference count increased. */ 89 | struct ktf_map_elem *ktf_map_find_first(struct ktf_map *map); 90 | 91 | /* Find the next element in the map after 'elem' if any. Decreases refcount 92 | * for "elem" and increases it for returned map element - this helps manage 93 | * reference counts when iterating over map elements. 94 | */ 95 | struct ktf_map_elem *ktf_map_find_next(struct ktf_map_elem *elem); 96 | 97 | /* Remove the element 'key' from the map and return a pointer to it with 98 | * refcount increased. 99 | */ 100 | struct ktf_map_elem *ktf_map_remove(struct ktf_map *map, const char *key); 101 | 102 | /* Remove specific element elem from the map. Refcount is not increased 103 | * as caller must already have had a reference. 104 | */ 105 | void ktf_map_remove_elem(struct ktf_map *map, struct ktf_map_elem *elem); 106 | 107 | void ktf_map_delete_all(struct ktf_map *map); 108 | 109 | static inline size_t ktf_map_size(struct ktf_map *map) { 110 | return map->size; 111 | } 112 | 113 | static inline bool ktf_map_empty(struct ktf_map *map) { 114 | return map->size == 0; 115 | } 116 | 117 | /* Gets first entry with refcount of entry increased for caller. */ 118 | #define ktf_map_first_entry(_map, _type, _member) \ 119 | ktf_map_empty(_map) ? NULL : \ 120 | container_of(ktf_map_find_first(_map), _type, _member) 121 | 122 | /* Gets next elem after "pos", decreasing refcount for pos and increasing 123 | * it for returned entry. 124 | */ 125 | #define ktf_map_next_entry(_pos, _member) ({ \ 126 | struct ktf_map_elem *_e = ktf_map_find_next(&(_pos)->_member); \ 127 | _e ? container_of(_e, typeof(*_pos), _member) : NULL; \ 128 | }) 129 | 130 | /* Iterates over map elements, incrementing refcount for current element and 131 | * decreasing it when we iterate to the next element. Important - if you 132 | * break out of the loop via break/return, ensure ktf_map_elem_put(pos) 133 | * is called for current element since we have a reference to it for the 134 | * current loop body iteration. 135 | */ 136 | #define ktf_map_for_each(pos, map) \ 137 | for (pos = ktf_map_find_first(map); pos != NULL; pos = ktf_map_find_next(pos)) 138 | 139 | /* Iterate over map elements in similar manner as above but using 140 | * container_of() wrappers to work with the type embedding a 141 | * "struct ktf_map_elem". 142 | */ 143 | #define ktf_map_for_each_entry(_pos, _map, _member) \ 144 | for (_pos = ktf_map_first_entry(_map, typeof(*_pos), _member); \ 145 | _pos != NULL; \ 146 | _pos = ktf_map_next_entry(_pos, _member)) 147 | 148 | #define ktf_map_find_entry(_map, _key, _type, _member) ({ \ 149 | struct ktf_map_elem *_entry = ktf_map_find(_map, _key); \ 150 | _entry ? container_of(_entry, _type, _member) : NULL; \ 151 | }) 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /kernel/ktf_netctx.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf_netcfg.h: Configurable context setup for multinode network tests 7 | * 8 | */ 9 | 10 | #include "ktf.h" 11 | #include "ktf_netctx.h" 12 | #include 13 | 14 | /* Configuration callback to configure a network context */ 15 | 16 | int ktf_netctx_cb(struct ktf_context *ctx, const void *data, size_t data_sz) 17 | { 18 | struct ktf_netctx *nc = container_of(ctx, struct ktf_netctx, k); 19 | struct ktf_addrinfo *kai = (struct ktf_addrinfo *)data; 20 | short n = kai->n; 21 | size_t param_sz; 22 | 23 | if (n < 2) { 24 | terr("Unsupported number of nodes (%d) - must be at least 2", n); 25 | return -EINVAL; 26 | } 27 | 28 | param_sz = sizeof(*kai) + sizeof(kai->a) * (n - 2); 29 | 30 | if (n > nc->max_nodes || n < nc->min_nodes) { 31 | terr("Unsupported number of nodes (%d) - must be between %d and %d!", 32 | n, nc->min_nodes, nc->max_nodes); 33 | return -EINVAL; 34 | } 35 | 36 | if (param_sz != data_sz) { 37 | terr("Expected %lu bytes of parameter data, received %lu!", 38 | param_sz, data_sz); 39 | return -EINVAL; 40 | } 41 | 42 | if (nc->a && nc->a_sz != data_sz) { 43 | kfree(nc->a); 44 | nc->a = NULL; 45 | } 46 | 47 | if (!nc->a) { 48 | nc->a = kzalloc(data_sz, GFP_KERNEL); 49 | if (!nc->a) 50 | return -ENOMEM; 51 | } 52 | 53 | memcpy(nc->a, kai, data_sz); 54 | return 0; 55 | } 56 | EXPORT_SYMBOL(ktf_netctx_cb); 57 | 58 | void ktf_netctx_cleanup(struct ktf_context *ctx) 59 | { 60 | struct ktf_netctx *nc = container_of(ctx, struct ktf_netctx, k); 61 | 62 | kfree(nc->a); 63 | } 64 | EXPORT_SYMBOL(ktf_netctx_cleanup); 65 | 66 | /* Make network contexts dynamically allocatable from user mode 67 | * Caller must supply desired values for callback functions in @nct. 68 | */ 69 | int ktf_netctx_enable(struct ktf_handle *handle, struct ktf_netctx_type *nct, 70 | short min_nodes, short max_nodes) 71 | { 72 | struct ktf_context *lo_ctx; 73 | struct ktf_addrinfo ai = { 74 | .n = 2, 75 | .rank = 0 76 | }; 77 | int ret; 78 | int i; 79 | 80 | ret = ktf_handle_add_ctx_type(handle, &nct->t); 81 | if (ret) 82 | return ret; 83 | 84 | nct->min_nodes = min_nodes; 85 | nct->max_nodes = max_nodes; 86 | strcpy(nct->t.name, "netctx"); 87 | 88 | for (i = 0; i < 2; i++) { 89 | struct sockaddr_in *ai_in = (struct sockaddr_in *)&ai.a[i].addr; 90 | 91 | ai.a[i].addr.ss_family = AF_INET; 92 | strcpy(ai.a[i].ifname, "lo"); 93 | ai_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 94 | } 95 | 96 | /* create and configure the loopback network context */ 97 | lo_ctx = ktf_context_add_from(handle, "lo", &nct->t); 98 | if (!lo_ctx) 99 | return -ENOMEM; 100 | 101 | ret = ktf_context_set_config(lo_ctx, &ai, sizeof(ai)); 102 | if (ret) 103 | return ret; 104 | 105 | return 0; 106 | } 107 | EXPORT_SYMBOL(ktf_netctx_enable); 108 | 109 | struct sockaddr_storage *ktf_netctx_addr(struct ktf_netctx *ctx, short rank) 110 | { 111 | return &ctx->a->a[rank].addr; 112 | } 113 | EXPORT_SYMBOL(ktf_netctx_addr); 114 | 115 | const char *ktf_netctx_ifname(struct ktf_netctx *ctx, short rank) 116 | { 117 | return ctx->a->a[rank].ifname; 118 | } 119 | EXPORT_SYMBOL(ktf_netctx_ifname); 120 | 121 | short ktf_netctx_rank(struct ktf_netctx *ctx) 122 | { 123 | return ctx->a->rank; 124 | } 125 | EXPORT_SYMBOL(ktf_netctx_rank); 126 | 127 | short ktf_netctx_n(struct ktf_netctx *ctx) 128 | { 129 | return ctx->a->n; 130 | } 131 | EXPORT_SYMBOL(ktf_netctx_n); 132 | -------------------------------------------------------------------------------- /kernel/ktf_netctx.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf_netctx.h: Configurable context setup for multinode network tests 7 | * 8 | * KTF implements handling on the kernel side for this but leaves 9 | * user space implementation to construct the corresponding 10 | * stuct ktf_addrinfo parameter block 11 | */ 12 | 13 | #ifndef _KTF_NETCTX_H 14 | #define _KTF_NETCTX_H 15 | 16 | /* KTF matches against this type id as a possible discriminator: */ 17 | #define KTF_NETCTX_TYPE_ID 0x2222 18 | 19 | #define IFNAMSZ 16 20 | 21 | struct ktf_peer_address 22 | { 23 | struct sockaddr_storage addr; /* Address to use for this peer */ 24 | char ifname[IFNAMSZ]; /* Local name of the interface with this address at peer */ 25 | }; 26 | 27 | struct ktf_addrinfo 28 | { 29 | short n; /* Number of nodes involved, including the local */ 30 | short rank; /* Index into ktf_peer_address that corresponds to local host */ 31 | struct ktf_peer_address a[2]; /* KTF expects size n instead of 2 here */ 32 | }; 33 | 34 | #ifdef __KERNEL__ 35 | 36 | struct ktf_netctx { 37 | struct ktf_context k; 38 | struct ktf_addrinfo *a; /* Addr.info dyn.allocated based on incoming data */ 39 | size_t a_sz; /* Size of the allocation in a, if any */ 40 | short min_nodes; /* Minimum number of nodes for this context */ 41 | short max_nodes; /* Maximum number of nodes this context supports */ 42 | }; 43 | 44 | struct ktf_netctx_type { 45 | struct ktf_context_type t; 46 | short min_nodes; /* Minimum number of nodes for the context type */ 47 | short max_nodes; /* Maximum number of nodes for the context type */ 48 | }; 49 | 50 | int ktf_netctx_enable(struct ktf_handle *handle, struct ktf_netctx_type *nct, 51 | short min_nodes, short max_nodes); 52 | 53 | int ktf_netctx_cb(struct ktf_context *ctx, const void *data, size_t data_sz); 54 | void ktf_netctx_cleanup(struct ktf_context *ctx); 55 | 56 | struct sockaddr_storage *ktf_netctx_addr(struct ktf_netctx *ctx, short rank); 57 | const char *ktf_netctx_ifname(struct ktf_netctx *ctx, short rank); 58 | short ktf_netctx_rank(struct ktf_netctx *ctx); 59 | short ktf_netctx_n(struct ktf_netctx *ctx); 60 | 61 | #endif 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /kernel/ktf_nl.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * nl.h: ktf netlink protocol interface 7 | */ 8 | #ifndef KTF_NL_H 9 | #define KTF_NL_H 10 | 11 | int ktf_nl_register(void); 12 | void ktf_nl_unregister(void); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /kernel/ktf_override.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Alan Maguire 5 | * 6 | * ktf_override.c: support for overriding function entry. 7 | */ 8 | #include 9 | #include 10 | #include "ktf.h" 11 | #include "ktf_override.h" 12 | 13 | asmlinkage void ktf_just_return_func(void); 14 | 15 | asm( 16 | ".type ktf_just_return_func, @function\n" 17 | ".globl ktf_just_return_func\n" 18 | "ktf_just_return_func:\n" 19 | " ret\n" 20 | ".size ktf_just_return_func, .-ktf_just_return_func\n" 21 | ); 22 | 23 | void ktf_post_handler(struct kprobe *kp, struct pt_regs *regs, 24 | unsigned long flags) 25 | { 26 | /* 27 | * A dummy post handler is required to prohibit optimizing, because 28 | * jump optimization does not support execution path overriding. 29 | */ 30 | } 31 | EXPORT_SYMBOL(ktf_post_handler); 32 | 33 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) 34 | static void *ktf_find_current_kprobe_sym(void) 35 | { 36 | return ktf_find_symbol(NULL, "current_kprobe"); 37 | } 38 | 39 | /* Prior to Linux 4.19, error exit does not clear active kprobe; as a result, 40 | * every page fault would fail due to logic in page fault handling activated 41 | * when a kprobe is active. We clean up by setting per-cpu variable 42 | * "current_kprobe" to NULL ourselves. 43 | */ 44 | #endif 45 | void ktf_override_function_with_return(struct pt_regs *regs) 46 | { 47 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) 48 | const struct kprobe __percpu **current_kprobe_ref; 49 | void *current_kprobe_sym = ktf_find_current_kprobe_sym(); 50 | 51 | if (!current_kprobe_sym) 52 | return; 53 | 54 | preempt_disable(); 55 | current_kprobe_ref = raw_cpu_ptr(current_kprobe_sym); 56 | if (*current_kprobe_ref) 57 | *current_kprobe_ref = NULL; 58 | preempt_enable(); 59 | #endif 60 | KTF_SET_INSTRUCTION_POINTER(regs, (unsigned long)&ktf_just_return_func); 61 | } 62 | EXPORT_SYMBOL(ktf_override_function_with_return); 63 | NOKPROBE_SYMBOL(ktf_override_function_with_return); 64 | 65 | int ktf_register_override(struct kprobe *kp) 66 | { 67 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) 68 | /* We can only support override if we can fix current_kprobe setting in 69 | * ktf_override_function_with_return(). To do that we need access to 70 | * the "current_kprobe" symbol address. If a kernel has been compiled 71 | * with CONFIG_KALLSYMS_ALL=n this will not be accessible, so fail at 72 | * registration time. 73 | */ 74 | if (!ktf_find_current_kprobe_sym()) 75 | return -ENOTSUPP; 76 | #endif 77 | return register_kprobe(kp); 78 | } 79 | EXPORT_SYMBOL(ktf_register_override); 80 | -------------------------------------------------------------------------------- /kernel/ktf_override.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Alan Maguire 5 | * 6 | * ktf_override.h: Function override support interface for KTF. 7 | */ 8 | #include 9 | #include "ktf.h" 10 | 11 | void ktf_post_handler(struct kprobe *kp, struct pt_regs *regs, 12 | unsigned long flags); 13 | void ktf_override_function_with_return(struct pt_regs *regs); 14 | int ktf_register_override(struct kprobe *kp); 15 | -------------------------------------------------------------------------------- /kernel/ktf_unlproto.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf_unlproto.h: implements interfaces for user-kernel netlink interactions 7 | * for querying/running tests. 8 | */ 9 | #ifndef _KTF_UNLPROTO_H 10 | #define _KTF_UNLPROTO_H 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | /* supported commands */ 16 | enum ktf_cmd { 17 | KTF_C_UNSPEC, 18 | KTF_C_QUERY, /* Query for a list of tests */ 19 | KTF_C_RUN, /* Run a test */ 20 | KTF_C_COV, /* Enable/disable coverage support */ 21 | KTF_C_CTX_CFG, /* Configure a context */ 22 | KTF_C_MAX, 23 | }; 24 | 25 | /* Netlink protocol definition shared between user and kernel space 26 | * Include once per user app as it defines struct values! 27 | 28 | * Each of the above commands issues from user space are responded to by the kernel 29 | * with the same command ID, but the kernel and user side messages have 30 | * different structure. See BNF syntax below for details. 31 | * 32 | * QUERY: 33 | * ------ 34 | * The QUERY request message is simply a VERSION attribute encoded according to the KTF_VERSION 35 | * macro below. All messages require this version number as a sanity check. 36 | * 37 | * The QUERY response from the kernel contains a list (HLIST attribute) of 38 | * - available handles (handle IDs(HID), each with an optional list (LIST attribute) 39 | * of associated contexts with context names in STR and and an optional context type 40 | * with name in MOD, and the status of the context (unconfigured, configured ok, or errno) 41 | * in the STAT attribute. 42 | * - all existing test suites/sets tests and their names as a list using LIST with a nested 43 | * list of TEST lists, each representing a test suite and corresponding tests and associated 44 | * test handle: 45 | * 46 | * ::= VERSION 47 | * 48 | * ::= VERSION [ ] NUM [ ] 49 | * ::= HLIST + 50 | * ::= HID [ ] 51 | * ::= LIST + + 52 | * ::= FILE 53 | * ::= STR [ MOD ] STAT 54 | * ::= LIST + 55 | * ::= STR TEST + 56 | * ::= HID STR 57 | * 58 | * 59 | * RUN: 60 | * ---- 61 | * A RUN request currently specifies a run of a single named test. A test is identified 62 | * by a test SNAME (set/suite name) a TNAM (test name) and an optional context (STR attribute) 63 | * to run it in. In addition tests can be arbitrarily parameterized, so tests optionally 64 | * allow out-of-band data via a DATA binary attribute. 65 | * The kernel response is a global status (in STAT) pluss an optional set of test results 66 | * eg. it supports running multiple tests, but this is not currently used. 67 | * 68 | * Each test result contains an optional list of individual error reports and 69 | * which each contains file name (FILE), line number (NUM) and a formatted error report string. 70 | * In addition each test result reports the number of assertions that were executed in the STAT 71 | * attribute: 72 | * 73 | * ::= VERSION SNAM TNAM [ STR ][ DATA ] 74 | * ::= STAT LIST 75 | * ::= STAT [ LIST + ] 76 | * ::= STAT FILE NUM STR 77 | * 78 | * COV: 79 | * ---- 80 | * A COV request is currently used to either enable or disable (NUM = 1/0) 81 | * coverage support for a particular module given by MOD, with option 82 | * flags (COVOPT): 83 | * 84 | * ::= VERSION MOD NUM [ COVOPT ] 85 | * ::= NUM STAT 86 | * 87 | * CTX_CFG: 88 | * -------- 89 | * A context configuration (CTX_CFG) request is used to configure the kernel side 90 | * of a context with the necessary parameters (context type specific data) provided 91 | * in a DATA attribute. The optional context type parameter (FILE attribute) 92 | * can be used to reference a context type, to dynamically create a new context 93 | * if the name given as STR does not exist. 94 | * The kernel currently does not send any response data to the user, 95 | * but tests will obviously subsequently fail if the context is not properly 96 | * configured: 97 | * 98 | * ::= VERSION STR HID DATA [ FILE ] 99 | * 100 | */ 101 | 102 | /* supported attributes */ 103 | enum ktf_attr { 104 | KTF_A_UNSPEC, 105 | KTF_A_VERSION,/* KTF version */ 106 | KTF_A_SNAM, /* Test suite name */ 107 | KTF_A_TNAM, /* Test name */ 108 | KTF_A_NUM, 109 | KTF_A_STR, 110 | KTF_A_FILE, 111 | KTF_A_STAT, 112 | KTF_A_LIST, 113 | KTF_A_TEST, 114 | KTF_A_HID, /* Test handle ID */ 115 | KTF_A_HLIST, /* List of handles repr. as a LIST of contexts for a given HID */ 116 | KTF_A_MOD, /* module for coverage analysis, also used for context type */ 117 | KTF_A_COVOPT, /* options for coverage analysis */ 118 | KTF_A_DATA, /* Binary data used by a.o. hybrid tests */ 119 | KTF_A_MAX 120 | }; 121 | 122 | /* attribute policy */ 123 | #ifdef NL_INTERNAL 124 | static struct nla_policy ktf_gnl_policy[KTF_A_MAX] = { 125 | [KTF_A_VERSION] = { .type = NLA_U64 }, 126 | [KTF_A_SNAM] = { .type = NLA_STRING }, 127 | [KTF_A_TNAM] = { .type = NLA_STRING }, 128 | [KTF_A_NUM] = { .type = NLA_U32 }, 129 | [KTF_A_STAT] = { .type = NLA_U32 }, 130 | [KTF_A_HID] = { .type = NLA_U32 }, 131 | [KTF_A_LIST] = { .type = NLA_NESTED }, 132 | [KTF_A_TEST] = { .type = NLA_NESTED }, 133 | [KTF_A_HLIST] = { .type = NLA_NESTED }, 134 | [KTF_A_STR] = { .type = NLA_STRING }, 135 | [KTF_A_FILE] = { .type = NLA_STRING }, 136 | [KTF_A_MOD] = { .type = NLA_STRING }, 137 | [KTF_A_COVOPT] = { .type = NLA_U32 }, 138 | [KTF_A_DATA] = { .type = NLA_BINARY }, 139 | }; 140 | #endif 141 | 142 | enum ktf_vshift { 143 | KTF_VSHIFT_BUILD = 0, 144 | KTF_VSHIFT_MICRO = 16, 145 | KTF_VSHIFT_MINOR = 32, 146 | KTF_VSHIFT_MAJOR = 48 147 | }; 148 | 149 | #define KTF_VERSION(__field, __v) \ 150 | ((__v & (0xffffULL << KTF_VSHIFT_##__field)) \ 151 | >> KTF_VSHIFT_##__field) 152 | 153 | #define KTF_VERSION_SET(__field, __v) \ 154 | ((__v & 0xffffULL) << KTF_VSHIFT_##__field) 155 | 156 | #define KTF_VERSION_LATEST \ 157 | (KTF_VERSION_SET(MAJOR, 0ULL) | KTF_VERSION_SET(MINOR, 2ULL) | KTF_VERSION_SET(MICRO, 1ULL)) 158 | 159 | /* Coverage options */ 160 | #define KTF_COV_OPT_MEM 0x1 161 | 162 | struct nla_policy *ktf_get_gnl_policy(void); 163 | 164 | #ifdef __cplusplus 165 | } 166 | #endif 167 | #endif 168 | -------------------------------------------------------------------------------- /kernel/runchecks.cfg: -------------------------------------------------------------------------------- 1 | checker checkpatch 2 | 3 | # We deliberately allow these: 4 | pervasive LINUX_VERSION_CODE 5 | 6 | # Older kernels fail on the SPDX license tag which now uses //: 7 | pervasive C99_COMMENTS 8 | 9 | # We allow this one as it catches all the LINUX_VERSION_CODE comparisons 10 | # and swaps them, which does not really feel natural, so we are willing to take the cost: 11 | pervasive CONSTANT_COMPARISON 12 | 13 | # Exception - detailed statement list needed for logging: 14 | except PREFER_PR_LEVEL ktf_test.c 15 | except PRINTK_WITHOUT_KERN_LEVEL ktf_test.c 16 | 17 | # Exception - checkpatch gets confused by the macro used to define the symbol: 18 | except EXPORT_SYMBOL ktf_cov.c 19 | 20 | # Exception - no good way to satisfy checkpatch for this asm()? 21 | except OPEN_ENDED_LINE ktf_override.c 22 | 23 | # Fails on bw compat code to avoid itself: 24 | except NEEDLESS_IF ktf_cov.c 25 | 26 | checker smatch 27 | 28 | # This looks like a false hit: 29 | except UNREACHABLE ktf_test.c 30 | 31 | checker sparse 32 | 33 | # sparse does not get the conditional lock/unlock: 34 | except CONTEXT ktf_context.c 35 | 36 | # sparse does not like our hack to overwrite the current_kprobe in 37 | # kernels older than 4.19.0 38 | except ADDRESS_SPACE ktf_override.c 39 | except ARG_TYPE_MOD ktf_override.c 40 | 41 | # sparse produce errors for this from slab.h in 4.20: 42 | except DUBIOUS_EXPR ktf_test.c ktf_cov.c ktf_netctx.c ktf_context.c 43 | -------------------------------------------------------------------------------- /lib/Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | 3 | ACLOCAL_AMFLAGS = -I m4 4 | 5 | AM_CFLAGS = -I$(top_srcdir) $(NETLINK_CFLAGS) $(GTEST_CFLAGS) \ 6 | -Wall -Werror -Wno-packed-bitfield-compat -D_GNU_SOURCE 7 | AM_CXXFLAGS = -I$(top_srcdir) $(NETLINK_CFLAGS) $(KTF_CXXFLAGS) \ 8 | -Wall \ 9 | -Wno-packed-bitfield-compat \ 10 | -Wno-pointer-arith -Werror \ 11 | -D__FILENAME__=\"`basename $<`\" 12 | 13 | lib_LTLIBRARIES = libktf.la 14 | libktf_la_SOURCES = ktf_int.cpp ktf_run.cpp ktf_unlproto.c ktf_debug.cpp 15 | 16 | libktf_includedir = $(includedir) 17 | libktf_include_HEADERS = ktf_debug.h ktf_int.h ktf.h 18 | 19 | ## Extra header files for the kernel side: 20 | 21 | KTF_K_HDRS = \ 22 | ktf.h \ 23 | ktf_test.h \ 24 | ktf_map.h \ 25 | ktf_override.h \ 26 | ktf_nl.h \ 27 | ktf_unlproto.h \ 28 | ktf_netctx.h \ 29 | ktf_compat.h 30 | 31 | kernel_headers_src = $(KTF_K_HDRS:%=$(top_srcdir)/kernel/%) 32 | kernel_headers = $(KTF_K_HDRS:%=$(includedir)/ktf/%) 33 | symvers = $(includedir)/ktf/Module.symvers 34 | scripts = $(includedir)/ktf/resolve 35 | 36 | $(kernel_headers): $(includedir)/ktf/%: $(top_srcdir)/kernel/% 37 | @mkdir -p `dirname $@` 38 | $(INSTALL) $< $@ 39 | 40 | $(symvers): $(includedir)/ktf/%: $(top_builddir)/kernel/% 41 | @mkdir -p `dirname $@` 42 | $(INSTALL) $< $@ 43 | 44 | $(scripts): $(includedir)/ktf/%: $(top_builddir)/scripts/% 45 | @mkdir -p `dirname $@` 46 | $(INSTALL) $< $@ 47 | 48 | install-data-local: $(kernel_headers) $(symvers) $(scripts) 49 | 50 | 51 | echo: 52 | @echo $(kernel_headers) $(symvers) 53 | -------------------------------------------------------------------------------- /lib/ktf.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf.h: User mode side of KTF extensions to the gtest unit test framework. 7 | * Include this to write hybrid tests 8 | * 9 | */ 10 | #ifndef _KTF_H 11 | #define _KTF_H 12 | #include 13 | 14 | namespace ktf 15 | { 16 | 17 | /* Interfaces intended to be used directly by programs: 18 | * ---------------------------------------------------- 19 | */ 20 | class KernelTest; 21 | 22 | /* Invoke the kernel test - to be called directly from user mode 23 | * hybrid tests: 24 | */ 25 | void run(KernelTest* kt, std::string ctx = ""); 26 | 27 | /* Function for enabling/disabling coverage for module */ 28 | int set_coverage(std::string module, unsigned int opts, bool enabled); 29 | 30 | typedef void (*configurator)(void); 31 | 32 | // Initialize KTF: 33 | // If necessary, supply a callback that uses the KTF_CONTEXT_CFG* macros below 34 | // to configure any necessary contexts: 35 | void setup(configurator c = NULL); 36 | 37 | } // end namespace ktf 38 | 39 | /* HTEST: Define user part of a hybrid test. 40 | * Hybrid tests are tests that have a user and a kernel counterpart, 41 | * to allow testing of interaction between user mode and the kernel: 42 | */ 43 | #define HTEST(__setname,__testname) \ 44 | class __setname ## _ ## __testname : public ktf::test_cb \ 45 | {\ 46 | public:\ 47 | __setname ## _ ## __testname() {\ 48 | ktf::add_wrapper(#__setname,#__testname,as_test_cb()); \ 49 | }\ 50 | virtual void fun(ktf::KernelTest* kt); \ 51 | }; \ 52 | __setname ## _ ## __testname \ 53 | __setname ## _ ## __testname ## _value;\ 54 | void __setname ## _ ## __testname::fun(ktf::KernelTest* self) 55 | 56 | 57 | /* Part of KTF support for hybrid tests: allocate/get a reference to 58 | * an out-of-band user data pointer: 59 | */ 60 | #define KTF_USERDATA(__kt_ptr, __priv_datatype, __priv_data) \ 61 | struct __priv_datatype *__priv_data = \ 62 | (struct __priv_datatype *)get_priv(__kt_ptr, sizeof(struct __priv_datatype)); \ 63 | ASSERT_TRUE(__priv_data); \ 64 | ASSERT_EQ(get_priv_sz(__kt_ptr), sizeof(struct __priv_datatype)) 65 | 66 | /* KTF support for configurable contexts: 67 | * Send a configuation data structure to the given context name. 68 | */ 69 | #define KTF_CONTEXT_CFG(__context_name, __context_type_name, __priv_datatype, __priv_data) \ 70 | ktf::configure_context(__context_name, __context_type_name, \ 71 | (struct __priv_datatype *)__priv_data, \ 72 | sizeof(__priv_datatype)) 73 | /* Alternative to KTF_CONTEXT_CFG: If there are multiple contexts with the same name 74 | * (but with different handles) use a test name to identify the context to be configured 75 | */ 76 | #define KTF_CONTEXT_CFG_FOR_TEST(__test_name, __context_type_name, __priv_datatype, __priv_data) \ 77 | ktf::configure_context_for_test(__test_name, __context_type_name, \ 78 | (struct __priv_datatype *)__priv_data, \ 79 | sizeof(__priv_datatype)) 80 | 81 | #define KTF_FIND(__setname, __testname, __context) \ 82 | ktf::find_test(__setname, __testname, __context) 83 | 84 | /* Private interfaces (needed by macro definitions above) 85 | * ------------------------------------------------------ 86 | */ 87 | 88 | namespace ktf { 89 | class test_cb 90 | { 91 | public: 92 | virtual ~test_cb() {} 93 | virtual test_cb* as_test_cb() { return this; } 94 | virtual void fun(KernelTest* kt) {} 95 | }; 96 | 97 | /* Function for adding a user level test wrapper */ 98 | void add_wrapper(const std::string setname, const std::string testname, 99 | test_cb* tcb); 100 | 101 | /* get a priv pointer of the given size, allocate if necessary */ 102 | void* get_priv(KernelTest* kt, size_t priv_sz); 103 | 104 | /* Get the size of the existing priv data */ 105 | size_t get_priv_sz(KernelTest *kt); 106 | 107 | // Configure ktf context - to be used via KTF_CONTEXT_CFG*(): 108 | void configure_context(const std::string context, const std::string type_name, 109 | void *data, size_t data_sz); 110 | void configure_context_for_test(const std::string testname, const std::string type_name, 111 | void *data, size_t data_sz); 112 | 113 | KernelTest* find_test(const std::string& setname, const std::string& testname, 114 | std::string* ctx); 115 | 116 | } // end namespace ktf 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /lib/ktf_debug.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2012 Oracle Corporation. All rights reserved 4 | * Author: Knut Omang 5 | */ 6 | 7 | #include "ktf_debug.h" 8 | #include 9 | 10 | unsigned long ktf_debug_mask = 0; 11 | 12 | 13 | void ktf_debug_init() 14 | { 15 | ktf_debug_mask = 0; 16 | char* dbg_mask_str = getenv("KTF_DEBUG_MASK"); 17 | if (dbg_mask_str) { 18 | ktf_debug_mask = strtol(dbg_mask_str, NULL, 0); 19 | log(KTF_INFO_V, "debug mask set to 0x%lx\n", ktf_debug_mask); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/ktf_debug.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2012 Oracle Corporation. All rights reserved 4 | * Author: Knut Omang 5 | * 6 | * ktf_debug.h: User mode debug function definitions 7 | * - intended for test debugging. 8 | * 9 | * Enabled by setting bits in the environment variable KTF_DEBUG_MASK 10 | */ 11 | 12 | #ifndef _KTF_DEBUG_H 13 | #define _KTF_DEBUG_H 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | extern unsigned long ktf_debug_mask; 22 | 23 | 24 | #define KTF_ERR 0x1 25 | #define KTF_WARN 0x2 26 | #define KTF_INFO 0x4 27 | #define KTF_INFO_V 0x100 28 | #define KTF_MR 0x2000 29 | #define KTF_DEBUG 0x10000 30 | #define KTF_POLL 0x20000 31 | #define KTF_EVENT 0x40000 32 | #define KTF_DEBUG_V 0x1000000 33 | #define KTF_DUMP 0x2000000 34 | 35 | /* Call this to initialize the debug logic from 36 | * environment KTF_DEBUG_MASK 37 | */ 38 | void ktf_debug_init(); 39 | 40 | #define log(level, format, arg...) \ 41 | do {\ 42 | if (level & ktf_debug_mask) {\ 43 | char _tm[30]; \ 44 | time_t _tv = time(NULL);\ 45 | ctime_r(&_tv,_tm);\ 46 | _tm[24] = '\0';\ 47 | fprintf(stderr, "%s [%ld] %s: " format, \ 48 | _tm, (long unsigned int) pthread_self(), __func__, ## arg); \ 49 | }\ 50 | } while (0) 51 | 52 | #define logs(class, stmt_list) \ 53 | do { \ 54 | if (ktf_debug_mask & class) { \ 55 | stmt_list; \ 56 | } \ 57 | } while (0) 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /lib/ktf_int.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf_int.h: User mode side of extension to the gtest unit test framework: 7 | * 1) Kernel test support via netlink 8 | * 2) Standard command line parameters 9 | * 10 | * This file exposes some internals - for users of hybrid tests including 11 | * ktf.h should be sufficient: 12 | */ 13 | 14 | #ifndef KTF_INT_H 15 | #define KTF_INT_H 16 | #include 17 | #include 18 | #include "ktf.h" 19 | 20 | typedef std::vector stringvec; 21 | 22 | namespace ktf 23 | { 24 | 25 | /* A callback handler to be called for each assertion result */ 26 | typedef void (*test_handler)(int result, const char* file, int line, const char* report); 27 | 28 | class KernelTest 29 | { 30 | public: 31 | KernelTest(const std::string& setname, const char* testname, unsigned int handle_id); 32 | ~KernelTest(); 33 | void* get_priv(size_t priv_sz); 34 | size_t get_priv_sz(KernelTest *kt); 35 | std::string setname; 36 | std::string testname; 37 | unsigned int handle_id; 38 | std::string name; 39 | size_t setnum; /* This test belongs to this set in the kernel */ 40 | size_t testnum; /* This test's index (test number) in the kernel */ 41 | void* user_priv; /* Optional private data for the test */ 42 | size_t user_priv_sz; /* Size of the user_priv data if used */ 43 | test_cb* user_test; /* Optional user level wrapper function for the kernel test */ 44 | char* file; 45 | int line; 46 | }; 47 | 48 | void *get_priv(KernelTest *kt, size_t priv_sz); 49 | 50 | // Set up connection to the kernel test driver: 51 | // @handle_test contains the test framework's handling code for test assertions */ 52 | bool setup(test_handler handle_test); 53 | 54 | void set_configurator(configurator c); 55 | 56 | // Parse command line args (call after gtest arg parsing) 57 | char** parse_opts(int argc, char** argv); 58 | 59 | /* Query kernel for available tests in index order */ 60 | stringvec& query_testsets(); 61 | 62 | stringvec get_testsets(); 63 | std::string get_current_setname(); 64 | stringvec get_test_names(); 65 | 66 | /* "private" - only run from gtest framework */ 67 | void run_test(KernelTest* test, std::string& ctx); 68 | } // end namespace ktf 69 | 70 | 71 | /* Redefine for C++ until we can get it patched - type mismatch by default */ 72 | #ifdef nla_for_each_nested 73 | #undef nla_for_each_nested 74 | #endif 75 | #define nla_for_each_nested(pos, nla, rem) \ 76 | for (pos = (struct nlattr*)nla_data(nla), rem = nla_len(nla); \ 77 | nla_ok(pos, rem); \ 78 | pos = nla_next(pos, &(rem))) 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /lib/ktf_run.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktf_run.cpp: 7 | * Gtest integration of ktf kernel tests - 8 | * e.g. tests that are fully implemented on the test driver side 9 | * and only initiated via run_test below 10 | */ 11 | 12 | #include "ktf_int.h" 13 | #include 14 | #include 15 | #include "ktf_debug.h" 16 | 17 | namespace ktf 18 | { 19 | 20 | class KernelMetaFactory; 21 | 22 | class Kernel : public ::testing::TestWithParam 23 | { 24 | public: 25 | Kernel() 26 | { 27 | assert(false); // Should not be hit but is needed for template resolving 28 | } 29 | 30 | Kernel(std::string& setname, std::string& testname) 31 | { 32 | log(KTF_INFO, "%s.%s\n", setname.c_str(), testname.c_str()); 33 | 34 | ukt = ktf::find_test(setname,testname,&ctx); 35 | if (!ukt) { 36 | fprintf(stderr, "**** Internal error: Could not find test %s.%s (set %s, name %s) ****\n", 37 | setname.c_str(), testname.c_str(), setname.c_str(), testname.c_str()); 38 | exit(7); 39 | } 40 | log(KTF_INFO, "### Kernel ctor %s (%ld,%ld)\n", ukt->name.c_str(), ukt->setnum, ukt->testnum); 41 | } 42 | 43 | virtual ~Kernel() 44 | { 45 | log(KTF_INFO, "### Kernel dtor %s\n", ukt->name.c_str()); 46 | 47 | /* For some reason errno sometimes get set 48 | * TBD: Figure out why - for now just reset it to avoid confusing the next test! 49 | */ 50 | if (errno) { 51 | log(KTF_INFO, "### %s: errno was set to %d - resetting..\n", ukt->name.c_str(), errno); 52 | errno = 0; 53 | } 54 | } 55 | 56 | virtual void TestBody(); 57 | private: 58 | ktf::KernelTest* ukt; 59 | std::string ctx; 60 | friend void setup(configurator c); 61 | static int AddToRegistry(); 62 | static configurator configurator_; 63 | }; 64 | 65 | 66 | 67 | class TFactory : public ::testing::internal::ParameterizedTestFactory 68 | { 69 | public: 70 | TFactory(std::string s, ParamType parameter) 71 | : ::testing::internal::ParameterizedTestFactory(parameter), 72 | setname(s) 73 | { 74 | testname = parameter.c_str(); 75 | } 76 | 77 | virtual ::testing::Test* CreateTest() 78 | { 79 | return new Kernel(setname,testname); 80 | } 81 | 82 | private: 83 | std::string setname; 84 | std::string testname; 85 | }; 86 | 87 | 88 | class KernelMetaFactory : public ::testing::internal::TestMetaFactory 89 | { 90 | public: 91 | virtual ::testing::internal::TestFactoryBase* CreateTestFactory(ParamType parameter) { 92 | TFactory* tf; 93 | std::string setname = get_current_setname(); 94 | tf = new TFactory(setname, parameter.c_str()); 95 | return tf; 96 | } 97 | }; 98 | 99 | testing::internal::ParamGenerator gtest_query_tests(void); 100 | std::string gtest_name_from_info(const testing::TestParamInfo&); 101 | void gtest_handle_test(int result, const char* file, int line, const char* report); 102 | 103 | #ifndef INSTANTIATE_TEST_SUITE_P 104 | /* This rename happens in Googletest commit 3a460a26b7. 105 | * Make sure we compile both before and after it: 106 | */ 107 | #define AddTestSuiteInstantiation AddTestCaseInstantiation 108 | #endif 109 | 110 | int Kernel::AddToRegistry() 111 | { 112 | if (!ktf::setup(ktf::gtest_handle_test)) return 1; 113 | 114 | /* Run query against kernel to figure out which tests that exists: */ 115 | stringvec& t = ktf::query_testsets(); 116 | 117 | ::testing::internal::ParameterizedTestCaseInfo* tci = 118 | ::testing::UnitTest::GetInstance()->parameterized_test_registry() 119 | .GetTestCasePatternHolder( "Kernel", ::testing::internal::CodeLocation("", 0)); 120 | 121 | for (stringvec::iterator it = t.begin(); it != t.end(); ++it) 122 | { 123 | ::testing::internal::TestMetaFactory* mf = new KernelMetaFactory(); 124 | #if HAVE_CODELOC_FOR_ADDTESTPATTERN 125 | tci->AddTestPattern(it->c_str(), "", mf, ::testing::internal::CodeLocation("", 0)); 126 | #else 127 | tci->AddTestPattern(it->c_str(), "", mf); 128 | #endif 129 | } 130 | 131 | tci->AddTestSuiteInstantiation("", >est_query_tests, >est_name_from_info, NULL, 0); 132 | return 0; 133 | } 134 | 135 | void setup(configurator c) 136 | { 137 | ktf::set_configurator(c); 138 | Kernel::AddToRegistry(); 139 | } 140 | 141 | 142 | void Kernel::TestBody() 143 | { 144 | run_test(ukt, ctx); 145 | } 146 | 147 | 148 | void gtest_handle_test(int result, const char* file, int line, const char* report) 149 | { 150 | if (result >= 0) { 151 | const ::testing::AssertionResult gtest_ar = 152 | !result ? (testing::AssertionFailure() << report) : testing::AssertionSuccess(); 153 | 154 | if (result) { 155 | /* We might get multiple partial results from the kernel in one positive 156 | * result report: 157 | */ 158 | #if HAVE_ASSERT_COUNT 159 | ::testing::UnitTest::GetInstance()->increment_success_assert_count(result); 160 | #else 161 | GTEST_SUCCEED(); 162 | #endif 163 | } else { 164 | ::testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure, 165 | file, line, gtest_ar.failure_message()) = ::testing::Message(); 166 | } 167 | } 168 | } 169 | 170 | testing::internal::ParamGenerator gtest_query_tests() 171 | { 172 | return testing::ValuesIn(ktf::get_test_names()); 173 | } 174 | 175 | std::string gtest_name_from_info(const testing::TestParamInfo& info) 176 | { 177 | return info.param; 178 | } 179 | 180 | } // end namespace ktf 181 | -------------------------------------------------------------------------------- /lib/ktf_unlproto.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * unlproto.c: This file is needed because the C struct init 7 | * used in kernel/unlproto.h is not allowed in C++ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #define NL_INTERNAL 1 14 | #include "kernel/ktf_unlproto.h" 15 | 16 | 17 | struct nla_policy *ktf_get_gnl_policy(void) 18 | { 19 | return ktf_gnl_policy; 20 | } 21 | -------------------------------------------------------------------------------- /m4/ax_check_compile_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the current language's compiler 12 | # or gives an error. (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the current language's default 18 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with 19 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to 20 | # force the compiler to issue an error when a bad flag is given. 21 | # 22 | # INPUT gives an alternative input source to AC_COMPILE_IFELSE. 23 | # 24 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 25 | # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Guido U. Draheim 30 | # Copyright (c) 2011 Maarten Bosmans 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 3 59 | 60 | AC_DEFUN([AX_CHECK_COMPILE_FLAG], 61 | [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX 62 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl 63 | AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ 64 | ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS 65 | _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" 66 | AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 67 | [AS_VAR_SET(CACHEVAR,[yes])], 68 | [AS_VAR_SET(CACHEVAR,[no])]) 69 | _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) 70 | AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], 71 | [m4_default([$2], :)], 72 | [m4_default([$3], :)]) 73 | AS_VAR_POPDEF([CACHEVAR])dnl 74 | ])dnl AX_CHECK_COMPILE_FLAGS 75 | 76 | 77 | # Convenience functions to add default compiler flags if they are supported 78 | # by the compiler: 79 | # 80 | AC_DEFUN([AX_CC_FLAG],[AX_CHECK_COMPILE_FLAG([$1],[CFLAGS="$CFLAGS $1"])]) 81 | 82 | AC_DEFUN([AX_CXX_FLAG], 83 | [AC_LANG_PUSH([C++]) 84 | AX_CHECK_COMPILE_FLAG([$1],[CXXFLAGS="$CXXFLAGS $1"]) 85 | AC_LANG_POP 86 | ]) 87 | 88 | -------------------------------------------------------------------------------- /m4/ltsugar.m4: -------------------------------------------------------------------------------- 1 | # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software 4 | # Foundation, Inc. 5 | # Written by Gary V. Vaughan, 2004 6 | # 7 | # This file is free software; the Free Software Foundation gives 8 | # unlimited permission to copy and/or distribute it, with or without 9 | # modifications, as long as this notice is preserved. 10 | 11 | # serial 6 ltsugar.m4 12 | 13 | # This is to help aclocal find these macros, as it can't see m4_define. 14 | AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) 15 | 16 | 17 | # lt_join(SEP, ARG1, [ARG2...]) 18 | # ----------------------------- 19 | # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their 20 | # associated separator. 21 | # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier 22 | # versions in m4sugar had bugs. 23 | m4_define([lt_join], 24 | [m4_if([$#], [1], [], 25 | [$#], [2], [[$2]], 26 | [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) 27 | m4_define([_lt_join], 28 | [m4_if([$#$2], [2], [], 29 | [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) 30 | 31 | 32 | # lt_car(LIST) 33 | # lt_cdr(LIST) 34 | # ------------ 35 | # Manipulate m4 lists. 36 | # These macros are necessary as long as will still need to support 37 | # Autoconf-2.59, which quotes differently. 38 | m4_define([lt_car], [[$1]]) 39 | m4_define([lt_cdr], 40 | [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], 41 | [$#], 1, [], 42 | [m4_dquote(m4_shift($@))])]) 43 | m4_define([lt_unquote], $1) 44 | 45 | 46 | # lt_append(MACRO-NAME, STRING, [SEPARATOR]) 47 | # ------------------------------------------ 48 | # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. 49 | # Note that neither SEPARATOR nor STRING are expanded; they are appended 50 | # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). 51 | # No SEPARATOR is output if MACRO-NAME was previously undefined (different 52 | # than defined and empty). 53 | # 54 | # This macro is needed until we can rely on Autoconf 2.62, since earlier 55 | # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. 56 | m4_define([lt_append], 57 | [m4_define([$1], 58 | m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) 59 | 60 | 61 | 62 | # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) 63 | # ---------------------------------------------------------- 64 | # Produce a SEP delimited list of all paired combinations of elements of 65 | # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list 66 | # has the form PREFIXmINFIXSUFFIXn. 67 | # Needed until we can rely on m4_combine added in Autoconf 2.62. 68 | m4_define([lt_combine], 69 | [m4_if(m4_eval([$# > 3]), [1], 70 | [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl 71 | [[m4_foreach([_Lt_prefix], [$2], 72 | [m4_foreach([_Lt_suffix], 73 | ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, 74 | [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) 75 | 76 | 77 | # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) 78 | # ----------------------------------------------------------------------- 79 | # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited 80 | # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. 81 | m4_define([lt_if_append_uniq], 82 | [m4_ifdef([$1], 83 | [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], 84 | [lt_append([$1], [$2], [$3])$4], 85 | [$5])], 86 | [lt_append([$1], [$2], [$3])$4])]) 87 | 88 | 89 | # lt_dict_add(DICT, KEY, VALUE) 90 | # ----------------------------- 91 | m4_define([lt_dict_add], 92 | [m4_define([$1($2)], [$3])]) 93 | 94 | 95 | # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) 96 | # -------------------------------------------- 97 | m4_define([lt_dict_add_subkey], 98 | [m4_define([$1($2:$3)], [$4])]) 99 | 100 | 101 | # lt_dict_fetch(DICT, KEY, [SUBKEY]) 102 | # ---------------------------------- 103 | m4_define([lt_dict_fetch], 104 | [m4_ifval([$3], 105 | m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), 106 | m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) 107 | 108 | 109 | # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) 110 | # ----------------------------------------------------------------- 111 | m4_define([lt_if_dict_fetch], 112 | [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], 113 | [$5], 114 | [$6])]) 115 | 116 | 117 | # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) 118 | # -------------------------------------------------------------- 119 | m4_define([lt_dict_filter], 120 | [m4_if([$5], [], [], 121 | [lt_join(m4_quote(m4_default([$4], [[, ]])), 122 | lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), 123 | [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl 124 | ]) 125 | -------------------------------------------------------------------------------- /m4/ltversion.m4: -------------------------------------------------------------------------------- 1 | # ltversion.m4 -- version numbers -*- Autoconf -*- 2 | # 3 | # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. 4 | # Written by Scott James Remnant, 2004 5 | # 6 | # This file is free software; the Free Software Foundation gives 7 | # unlimited permission to copy and/or distribute it, with or without 8 | # modifications, as long as this notice is preserved. 9 | 10 | # @configure_input@ 11 | 12 | # serial 4179 ltversion.m4 13 | # This file is part of GNU Libtool 14 | 15 | m4_define([LT_PACKAGE_VERSION], [2.4.6]) 16 | m4_define([LT_PACKAGE_REVISION], [2.4.6]) 17 | 18 | AC_DEFUN([LTVERSION_VERSION], 19 | [macro_version='2.4.6' 20 | macro_revision='2.4.6' 21 | _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) 22 | _LT_DECL(, macro_revision, 0) 23 | ]) 24 | -------------------------------------------------------------------------------- /m4/lt~obsolete.m4: -------------------------------------------------------------------------------- 1 | # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- 2 | # 3 | # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software 4 | # Foundation, Inc. 5 | # Written by Scott James Remnant, 2004. 6 | # 7 | # This file is free software; the Free Software Foundation gives 8 | # unlimited permission to copy and/or distribute it, with or without 9 | # modifications, as long as this notice is preserved. 10 | 11 | # serial 5 lt~obsolete.m4 12 | 13 | # These exist entirely to fool aclocal when bootstrapping libtool. 14 | # 15 | # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), 16 | # which have later been changed to m4_define as they aren't part of the 17 | # exported API, or moved to Autoconf or Automake where they belong. 18 | # 19 | # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN 20 | # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us 21 | # using a macro with the same name in our local m4/libtool.m4 it'll 22 | # pull the old libtool.m4 in (it doesn't see our shiny new m4_define 23 | # and doesn't know about Autoconf macros at all.) 24 | # 25 | # So we provide this file, which has a silly filename so it's always 26 | # included after everything else. This provides aclocal with the 27 | # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything 28 | # because those macros already exist, or will be overwritten later. 29 | # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 30 | # 31 | # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. 32 | # Yes, that means every name once taken will need to remain here until 33 | # we give up compatibility with versions before 1.7, at which point 34 | # we need to keep only those names which we still refer to. 35 | 36 | # This is to help aclocal find these macros, as it can't see m4_define. 37 | AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) 38 | 39 | m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) 40 | m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) 41 | m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) 42 | m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) 43 | m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) 44 | m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) 45 | m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) 46 | m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) 47 | m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) 48 | m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) 49 | m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) 50 | m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) 51 | m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) 52 | m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) 53 | m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) 54 | m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) 55 | m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) 56 | m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) 57 | m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) 58 | m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) 59 | m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) 60 | m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) 61 | m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) 62 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) 63 | m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) 64 | m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) 65 | m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) 66 | m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) 67 | m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) 68 | m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) 69 | m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) 70 | m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) 71 | m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) 72 | m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) 73 | m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) 74 | m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) 75 | m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) 76 | m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) 77 | m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) 78 | m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) 79 | m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) 80 | m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) 81 | m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) 82 | m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) 83 | m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) 84 | m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) 85 | m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) 86 | m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) 87 | m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) 88 | m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) 89 | m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) 90 | m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) 91 | m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) 92 | m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) 93 | m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) 94 | m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) 95 | m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) 96 | m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) 97 | m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) 98 | m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) 99 | m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) 100 | -------------------------------------------------------------------------------- /scripts/ktf_syms.mk: -------------------------------------------------------------------------------- 1 | ktf_symfile=$(shell (cd $(srctree)/$(src) && ls ktf_syms.txt 2> /dev/null || true)) 2 | ktf_syms = $(ktf_symfile:%.txt=%.h) 3 | 4 | ifneq ($(ktf_symfile),) 5 | 6 | $(obj)/self.o: $(obj)/$(ktf_syms) 7 | 8 | ktf_scripts = $(srctree)/$(src)/../scripts 9 | 10 | $(obj)/$(ktf_syms): $(srctree)/$(src)/ktf_syms.txt $(ktf_scripts)/resolve 11 | @echo " KTFSYMS $@" 12 | $(Q)$(ktf_scripts)/resolve $(ccflags-y) $< $@ 13 | 14 | clean-files += $(ktf_syms) 15 | 16 | endif 17 | -------------------------------------------------------------------------------- /scripts/ktfnew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # SPDX-License-Identifier: GPL-2.0 4 | # 5 | # Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 6 | # Author: Knut Omang 7 | # 8 | # A script to generate a new KTF test suite with configuration setup 9 | # and Makefile support for building out-of-tree. 10 | # 11 | 12 | import sys, os, shutil 13 | 14 | def usage(): 15 | print "Usage: %s [-p ] " % sys.argv[0] 16 | print " - Initialize a new ktf based test project called " 17 | print " Default is to populate a new directory called in the same directory" 18 | print " as where the ktf source tree is placed, assuming we are called from the source" 19 | exit(0) 20 | 21 | 22 | path_n = False 23 | usage_h = False 24 | my_argv = [] 25 | path = None 26 | 27 | # m4 files to install (ext .m4 assumed): 28 | # 29 | m4_filelist = [ "ktf", "ax_check_compile_flag" ] 30 | 31 | for arg in sys.argv[1:]: 32 | if arg == "-h": 33 | usage_h = True 34 | elif arg == "-p": 35 | path_n = True 36 | elif path_n: 37 | path = arg 38 | path_n = False 39 | else: 40 | my_argv.append(arg) 41 | 42 | if len(my_argv) != 1 or usage_h: 43 | usage() 44 | 45 | name = my_argv[0] 46 | ktf_scripts = os.path.dirname(sys.argv[0]) 47 | ktf_root = os.path.realpath(ktf_scripts + "/..") 48 | src_root = os.path.realpath(ktf_scripts + "/../..") 49 | 50 | if path == None: 51 | path = src_root 52 | target_root = "%s/%s" % (path, name) 53 | email = "myemail@example.com" 54 | 55 | print "Creating a new project under " + target_root 56 | 57 | try: 58 | os.makedirs(target_root) 59 | except OSError as exc: 60 | if exc.errno == os.errno.EEXIST: 61 | print " ** Project path %s already exists - giving up! **" % target_root 62 | exit(17) 63 | else: 64 | raise 65 | 66 | try: 67 | os.makedirs("%s/m4" % target_root) 68 | os.makedirs("%s/kernel" % target_root) 69 | # Install ktf.m4 and dependencies from the ktf source: 70 | fm = "%s/m4/%s.m4" 71 | for f in m4_filelist: 72 | shutil.copyfile(fm % (ktf_root,f), fm % (target_root, f)) 73 | 74 | # Create a minimal configure.ac 75 | # 76 | cfg_file = open("%s/configure.ac" % target_root, "w") 77 | cfg_file.write('''# Process this file with autoconf to produce a configure script.\n 78 | # Prelude:\nAC_PREREQ([2.59])\nAC_INIT([%s], [0.1], [%s])\n 79 | # unique source file --- primitive safety check 80 | AC_CONFIG_SRCDIR([kernel/%s.c])\n 81 | # place to put some extra build scripts installed 82 | AC_CONFIG_AUX_DIR([ac])\n 83 | # Look for/generate m4 files under top/m4 84 | AC_CONFIG_MACRO_DIR([m4])\n 85 | AM_INIT_AUTOMAKE([foreign -Wall -Werror])\n 86 | # Silent rules by default - use make V=1 for verbose 87 | AM_SILENT_RULES([yes])\n 88 | # Check for dependencies: 89 | AM_LIB_KTF\n 90 | # List directories containing ktf kernel module source: 91 | # (You can have more than one of these if you have modules in more than one directory:) 92 | AM_KTF_DIR([kernel]) 93 | AC_CONFIG_FILES([Makefile 94 | kernel/Makefile 95 | ]) 96 | AC_OUTPUT 97 | ''' % (name, email, name)) 98 | cfg_file.close() 99 | 100 | # Create a minimal toplevel automake file: 101 | am_file = open("%s/Makefile.am" % target_root, "w") 102 | am_file.write('''## Process this file with automake to produce Makefile.in\n 103 | ACLOCAL_AMFLAGS= -I m4\n 104 | SUBDIRS = kernel 105 | ''') 106 | am_file.close() 107 | 108 | # Create a kernel module Makefile input to autoconf as Makefile.in, 109 | # assume a single module source file .c : 110 | mfile = open("%s/kernel/Makefile.in" % target_root, "w") 111 | mfile.write(''' 112 | KVER = @KVER@ 113 | KTF_DIR = @KTF_DIR@ 114 | KTF_BDIR = @KTF_BDIR@ 115 | 116 | ccflags-y += -I$(KTF_DIR) 117 | 118 | obj-m := %s.o\n 119 | -include ktf_gen.mk\n 120 | KDIR := @KDIR@ 121 | PWD := $(shell pwd)\n 122 | EXTRASYMS := KBUILD_EXTRA_SYMBOLS="$(KTF_BDIR)/Module.symvers"\n 123 | module: 124 | $(MAKE) -C $(KDIR) M=$(PWD) $(EXTRASYMS) modules\n 125 | clean: 126 | $(MAKE) -C $(KDIR) M=$(PWD) clean\n 127 | check: all 128 | install: all 129 | ''' % name) 130 | mfile.close() 131 | 132 | # Create a simple module template: 133 | module = open("%s/kernel/%s.c" % (target_root, name), "w") 134 | module.write(''' 135 | #include \n#include "ktf.h"\n 136 | MODULE_LICENSE("GPL");\n 137 | KTF_INIT();\n 138 | TEST(simple, t1)\n{\n\tEXPECT_TRUE(true);\n}\n 139 | static void add_tests(void)\n{\n\tADD_TEST(t1);\n}\n 140 | static int __init %s_init(void)\n{\n\tadd_tests();\n\treturn 0;\n} 141 | static void __exit %s_exit(void)\n{\n\tKTF_CLEANUP();\n}\n 142 | module_init(%s_init); 143 | module_exit(%s_exit); 144 | ''' % (name, name, name, name) ) 145 | module.close() 146 | 147 | # Now run an intitial autoreconf to set things up: 148 | os.system("(cd %s && autoreconf -i 2> /dev/null)" % target_root) 149 | except: 150 | print " ** Error: ** " 151 | raise 152 | -------------------------------------------------------------------------------- /scripts/resolve: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # SPDX-License-Identifier: GPL-2.0 4 | # 5 | # Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 6 | # Author: Knut Omang 7 | # 8 | # A script to generate code and header definitions for 9 | # module and kernel symbols not directly exposed to KTF. 10 | # (See the documentation for KTF for details) 11 | # 12 | 13 | import os, sys, re, shutil, string 14 | 15 | def usage(): 16 | print("Usage: resolve symbolfile outputfile") 17 | exit(0) 18 | 19 | class ResolveError(Exception): 20 | def __init__(self, value): 21 | self.value = "resolve error: " + value 22 | def __str__(self): 23 | return repr(self.value) 24 | 25 | class FuncInfo: 26 | def __init__(self, sym, re_sym, re_decl): 27 | self.symbol = sym 28 | self.re_sym = re_sym 29 | self.re_decl = re_decl 30 | 31 | def __repr__(self): 32 | return "FuncInfo: [%s: %s]" % (self.symbol, self.re_decl) 33 | 34 | class Module: 35 | def __init__(self, name, header): 36 | self.cur_header = header 37 | self.prefix = "Z" 38 | self.name = name 39 | self.symbols = {} # Input: headerfile -> symbol list 40 | self.func_def = [] # FuncInfo list 41 | self.debug = False 42 | all_modules.append(self) 43 | 44 | def log(self, str): 45 | if self.debug: 46 | sys.stderr.write(str + "\n") 47 | 48 | def SetHeader(self, header): 49 | self.cur_header = header 50 | 51 | def AddSymbol(self, sym): 52 | try: 53 | h = self.symbols[self.cur_header] 54 | h.append(sym) 55 | except: 56 | self.symbols[self.cur_header] = [sym] 57 | 58 | # Open along include path: 59 | def Open(self, filename): 60 | for p in includepath: 61 | try: 62 | f = os.path.join(p, filename) 63 | self.log(" -- trying " + f) 64 | header = open(f,'r') 65 | return header 66 | except: 67 | continue 68 | sys.stderr.write(" ** unable to open \"%s\"\n" % filename) 69 | return None 70 | 71 | # Parse the relevant header files for function defs: 72 | def ParseDefs(self): 73 | for hf in self.symbols.keys(): 74 | self.log(" ** Parsing %s:" % hf) 75 | header = self.Open(hf) 76 | if header == None: 77 | return 78 | content = header.read() 79 | symbols = self.symbols[hf] 80 | types = r"(extern|u8|u16|u32|u64|int|long|size_t|off_t|loff_t|void|struct|union\s)(.*[\*\s]" 81 | funor = ")(" + "|".join(symbols) + r")(\([^\)]+\);)$" 82 | tt = types + funor 83 | s = re.compile(tt, re.MULTILINE) 84 | miter = s.finditer(content) 85 | s_count = 0 86 | for m in miter: 87 | sym = m.group(3) 88 | re_name = "_".join([self.prefix, sym]) 89 | re_decl = "%s%s(*%s)%s" % (m.group(1), m.group(2), re_name, m.group(4)) 90 | self.func_def.append(FuncInfo(sym, re_name, re_decl)) 91 | s_count = s_count + 1 92 | 93 | if s_count != len(symbols): 94 | print(" ** Warning: File %s: Found %d definitions from %d symbols!" % \ 95 | (hf, s_count, len(symbols))) 96 | print(" ** - please check/fix output manually!") 97 | 98 | # Output functions: 99 | def write_funcs(self, file): 100 | for fi in self.func_def: 101 | file.write("\t%s\n"% fi.re_decl) 102 | 103 | def write_defines(self, file): 104 | for fi in self.func_def: 105 | file.write("#define %s ktf_syms.%s\n" % (fi.symbol, fi.re_sym)) 106 | 107 | def write_resolve_calls(self, file): 108 | for fi in self.func_def: 109 | file.write("\tktf_resolve_symbol(%s, %s);\n" % (self.name, fi.symbol)) 110 | 111 | usage_h = False 112 | my_argv = [] 113 | includepath = [""] 114 | 115 | #sys.stderr.write("%s\n" % (sys.argv)) 116 | for arg in sys.argv[1:]: 117 | if arg == "-h": 118 | usage_h = True 119 | continue 120 | incl = re.match(r"-I([^\s]+)", arg) 121 | if incl != None: 122 | includepath.append(incl.group(1)) 123 | continue 124 | genopt = re.match(r"-([^\s]+)", arg) 125 | if genopt != None: 126 | # Silently ignore other cc options as we accept cc-flags-y: 127 | # 128 | continue 129 | my_argv.append(arg) 130 | 131 | # Main program: 132 | 133 | if len(my_argv) != 2 or usage_h: 134 | usage() 135 | 136 | symfile = my_argv[0] 137 | outputfile = my_argv[1] 138 | 139 | all_modules = [] 140 | module = Module("kernel", None) # Default, at the top of the file is the main kernel symbols 141 | header = None # A header directive is required before any symbols 142 | 143 | try: 144 | file = open(symfile, 'r') 145 | for line in file: 146 | match = re.match(r"^#(\w+) ([\w\.]+)\s*$", line) 147 | if match != None: 148 | cmd = match.group(1) 149 | value = match.group(2) 150 | if cmd == "module": 151 | module = Module(value, header) 152 | elif cmd == "header": 153 | header = value 154 | module.SetHeader(header) 155 | else: 156 | raise ResolveError("While parsing %s: Unknown directive \"%s\"" % (symfile, cmd)) 157 | #print("%s set to %s" % (cmd, value)) 158 | continue 159 | match = re.match(r"\s*(\w+)\s*", line) 160 | if match != None: 161 | s = match.group(1) 162 | module.AddSymbol(s) 163 | except ResolveError as e: 164 | print(e.value) 165 | exit(1) 166 | except: 167 | print("Unable to open config file \"%s\"" % symfile) 168 | exit(1) 169 | 170 | for m in all_modules: 171 | m.ParseDefs() 172 | 173 | try: 174 | output = open(outputfile, "w") 175 | except: 176 | print("Failed to open output header file \"%s\"" % outputfile) 177 | output.write('#ifndef _KTF_RESOLVE_H\n#define _KTF_RESOLVE_H\n') 178 | output.write('#include "ktf.h"\n\nstruct ktf_syms {\n') 179 | 180 | for m in all_modules: 181 | m.write_funcs(output) 182 | 183 | output.write('};\n\n') 184 | 185 | for m in all_modules: 186 | m.write_defines(output) 187 | 188 | output.write('\n\nextern struct ktf_syms ktf_syms;\n') 189 | output.write('\nint ktf_resolve_symbols(void);\n#ifndef KTF_CLIENT\n') 190 | output.write('struct ktf_syms ktf_syms;\n\n') 191 | 192 | output.write('\nint ktf_resolve_symbols(void)\n{\n') 193 | 194 | for m in all_modules: 195 | m.write_resolve_calls(output) 196 | 197 | output.write('\treturn 0;\n}\n\n#endif /* !KTF_CLIENT */\n#endif /* _KTF_RESOLVE_H */ \n') 198 | output.close() 199 | -------------------------------------------------------------------------------- /scripts/runtests.mk: -------------------------------------------------------------------------------- 1 | TEST_PROGS := scripts/runtests.sh 2 | 3 | include ../lib.mk 4 | -------------------------------------------------------------------------------- /scripts/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | verbose=1 4 | 5 | # Convenience function to return a string that 6 | # is a reverse list of the incoming arguments: 7 | # 8 | reverse() 9 | { 10 | args=($*) 11 | for (( i=((${#args[*]} - 1)); i >= 0; i-- )); do 12 | echo ${args[$i]} 13 | done 14 | } 15 | 16 | # Set paths to a particular module - if no path is set to a module, use modprobe: 17 | # 18 | declare -A a_mpath 19 | mpath() 20 | { 21 | local module="$1" 22 | local mpath="$2" 23 | [[ $mpath != "" ]] || fail "Usage: mpath module path" 24 | 25 | a_mpath[$module]="$BUILD/$mpath" 26 | } 27 | 28 | # Set parameters to load a given module with for test purposes: 29 | declare -A a_params 30 | params() 31 | { 32 | local module="$1" 33 | shift 34 | a_params[$module]="$*" 35 | } 36 | 37 | log() 38 | { 39 | (( $verbose )) && echo $* 40 | } 41 | 42 | mod_probe() 43 | { 44 | local fm="" 45 | local name="$1" 46 | shift 47 | 48 | mp=${a_mpath[$name]} 49 | if [[ $mp != "" ]]; then 50 | fm="$mp" 51 | fi 52 | 53 | is_loaded=$(lsmod | egrep "^$name" || true) 54 | if [[ $is_loaded != "" ]]; then 55 | echo "Module \"$name\" is already loaded!" 1>&2 56 | return 0 57 | fi 58 | 59 | if [[ $fm == "" ]]; then 60 | log "Modprobing $name" 61 | $sudo modprobe $name ${a_params[$name]} 62 | else 63 | fm=${a_mpath[$name]} 64 | log "Insmod'ing module \"$name\"" 1>&2 65 | $sudo insmod $fm ${a_params[$name]} 66 | fi 67 | } 68 | 69 | # If/when more modules are to be loaded, this could go in a config file 70 | # but for the purpose of this example, just do it inline: 71 | # 72 | mpath ktf ktf/kernel/ktf.ko 73 | mpath selftest ktf/selftest/selftest.ko 74 | 75 | load_modules="ktf selftest" 76 | 77 | unload_modules=$(reverse $load_modules) 78 | 79 | sudo="" 80 | if [[ $USER != "root" ]]; then 81 | sudo="sudo" 82 | fi 83 | 84 | for m in $load_modules; do 85 | mod_probe $m 86 | done 87 | 88 | if [[ $GTEST_PATH == "" ]];then 89 | echo "Set environment variable GTEST_PATH to point to your googletest build!" 90 | exit 1 91 | fi 92 | 93 | export LD_LIBRARY_PATH="$BUILD/ktf/lib:$GTEST_PATH/lib64:$GTEST_PATH/lib" 94 | $BUILD/ktf/user/ktftest || stat=$? 95 | 96 | for m in $unload_modules; do 97 | $sudo rmmod $m 98 | done 99 | 100 | exit $stat 101 | -------------------------------------------------------------------------------- /scripts/top_make.mk: -------------------------------------------------------------------------------- 1 | ifneq ($(TARGETS),) 2 | # We end up here if called from selftests/Makefile 3 | # Invoke our "module target" to get everything built 4 | all: 5 | $(Q)$(MAKE) -C $(abs_objtree) M=tools/testing/selftests/ktf 6 | 7 | clean: 8 | $(Q)$(MAKE) -C $(abs_objtree) M=tools/testing/selftests/ktf clean 9 | 10 | run_tests: 11 | @echo "running tests" 12 | $(MAKE) BUILD=$(abs_objtree)/tools/testing/selftests -f scripts/runtests.mk $@ 13 | 14 | endif 15 | -------------------------------------------------------------------------------- /selftest/Makefile.in: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # 3 | # Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. 4 | # 5 | # Kernel module implementing a test suite for testing KTF itself 6 | # 7 | 8 | ccflags-y += -Wno-vla 9 | 10 | KVER = @KVER@ 11 | KTF_DIR = @KTF_DIR@ 12 | KTF_BDIR = @KTF_BDIR@ 13 | 14 | ccflags-y += -I$(KTF_DIR) 15 | 16 | obj-m := selftest.o 17 | 18 | -include ktf_gen.mk 19 | 20 | selftest-y := self.o hybrid.o context.o 21 | 22 | KDIR := @KDIR@ 23 | PWD := $(shell pwd) 24 | 25 | EXTRASYMS := KBUILD_EXTRA_SYMBOLS="$(KTF_BDIR)/Module.symvers" 26 | 27 | module: 28 | $(MAKE) -C $(KDIR) M=$(PWD) $(EXTRASYMS) modules 29 | 30 | modules_install: 31 | $(MAKE) -C $(KDIR) M=$(PWD) $(EXTRASYMS) modules_install 32 | 33 | clean: 34 | $(MAKE) -C $(KDIR) M=$(PWD) clean 35 | 36 | check: all 37 | $(MAKE) -C $(KDIR) M=$(PWD) C=2 38 | -------------------------------------------------------------------------------- /selftest/context.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4 | * 5 | * context.c: Parameterized context test case, kernel side: 6 | */ 7 | 8 | #include "ktf.h" 9 | #include "context.h" 10 | 11 | /* Declare a specific handle for this test to avoid interfering with the 12 | * other tests: 13 | */ 14 | static KTF_HANDLE_INIT(ct_handle); 15 | 16 | struct param_test_ctx { 17 | struct ktf_context k; 18 | struct test_parameter_block p; 19 | }; 20 | 21 | struct param_test_ctx param_ctx[2]; 22 | 23 | #define MYVALUE 0xdabadaba 24 | 25 | /* Declare the callback that accepts a parameter block */ 26 | static int param_ctx_cb(struct ktf_context *ctx, const void *data, size_t data_sz) 27 | { 28 | struct param_test_ctx *px = container_of(ctx, struct param_test_ctx, k); 29 | struct test_parameter_block *pb = (struct test_parameter_block *)data; 30 | long orig_myvalue; 31 | 32 | if (data_sz != sizeof(*pb)) 33 | return -EINVAL; 34 | /* check data validity here, if possible.. */ 35 | orig_myvalue = px->p.myvalue; 36 | memcpy(&px->p, pb, data_sz); 37 | /* Enforce "policies" */ 38 | px->p.myvalue = orig_myvalue; 39 | return 0; 40 | } 41 | 42 | TEST(selftest, param) 43 | { 44 | struct param_test_ctx *px = container_of(ctx, struct param_test_ctx, k); 45 | 46 | /* Now, here we can fail (using ASSERT) or ignore by silently return 47 | * depending on what's most useful, if a test hasn't been configured. 48 | * For this selftest we just use EXPECT so we can have the actual current 49 | * parameter values reported as well. 50 | * 51 | * Notice that these parameters are 52 | * persistent throughout the instance 'life' of the kernel test module, 53 | * so if one user program has configured them, then 54 | * programs ignorant of the parameters may still end up 55 | * executing the tests with previously configured parameters: 56 | * 57 | * This simplified example uses the same configuration struct for both 58 | * context type IDs, but the idea is that they can be completely different. 59 | */ 60 | EXPECT_INT_EQ(ctx->config_errno, 0); 61 | if (KTF_CONTEXT_CFG_OK(ctx)) { 62 | switch (ctx->type->name[13]) { 63 | case '1': 64 | EXPECT_LONG_EQ(px->p.magic, CONTEXT_MAGIC1); 65 | break; 66 | case '2': 67 | EXPECT_LONG_EQ(px->p.magic, CONTEXT_MAGIC2); 68 | break; 69 | case '3': 70 | EXPECT_LONG_EQ(px->p.magic, CONTEXT_MAGIC3); 71 | EXPECT_LONG_EQ(px->p.myvalue, MYVALUE); 72 | break; 73 | } 74 | EXPECT_STREQ(px->p.s, CONTEXT_MSG); 75 | } else { 76 | EXPECT_LONG_EQ(px->p.magic, 0); 77 | EXPECT_STREQ(px->p.s, ""); 78 | } 79 | } 80 | 81 | struct param_test_type { 82 | struct ktf_context_type kt; 83 | /* space for cfg data (such as constraints) for the context type */ 84 | long myvalue; 85 | }; 86 | 87 | static struct ktf_context *type3_alloc(struct ktf_context_type *ct) 88 | { 89 | struct param_test_type *pct = container_of(ct, struct param_test_type, kt); 90 | struct param_test_ctx *ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 91 | 92 | ctx->p.myvalue = pct->myvalue; 93 | return &ctx->k; 94 | } 95 | 96 | static void type3_cleanup(struct ktf_context *ctx) 97 | { 98 | struct param_test_ctx *px = container_of(ctx, struct param_test_ctx, k); 99 | 100 | kfree(px); 101 | } 102 | 103 | TEST(selftest, dupltype) 104 | { 105 | /* Verify that we cannot add the same context type twice */ 106 | 107 | static struct param_test_type dupltype = { 108 | .myvalue = 0, 109 | .kt.alloc = type3_alloc, 110 | .kt.config_cb = param_ctx_cb, 111 | .kt.cleanup = type3_cleanup, 112 | .kt.name = "context_type_3" 113 | }; 114 | 115 | ASSERT_INT_EQ(-EEXIST, ktf_handle_add_ctx_type(&ct_handle, &dupltype.kt)); 116 | } 117 | 118 | void add_context_tests(void) 119 | { 120 | int ret = KTF_CONTEXT_ADD_TO_CFG(ct_handle, ¶m_ctx[0].k, "context1", 121 | param_ctx_cb, "context_type_1"); 122 | 123 | if (ret) 124 | return; 125 | 126 | ret = KTF_CONTEXT_ADD_TO_CFG(ct_handle, ¶m_ctx[1].k, "context2", 127 | param_ctx_cb, "context_type_2"); 128 | if (ret) 129 | return; 130 | 131 | { 132 | static struct param_test_type ctx_type3 = { 133 | .myvalue = MYVALUE, 134 | .kt.alloc = type3_alloc, 135 | .kt.config_cb = param_ctx_cb, 136 | .kt.cleanup = type3_cleanup, 137 | .kt.name = "context_type_3" 138 | }; 139 | ret = ktf_handle_add_ctx_type(&ct_handle, &ctx_type3.kt); 140 | } 141 | 142 | ADD_TEST_TO(ct_handle, param); 143 | ADD_TEST(dupltype); 144 | } 145 | 146 | void context_tests_cleanup(void) 147 | { 148 | KTF_HANDLE_CLEANUP(ct_handle); 149 | } 150 | -------------------------------------------------------------------------------- /selftest/context.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4 | * 5 | * context.h: Parameterized context test case, kernel side. 6 | */ 7 | #ifndef _CONTEXT_H 8 | #define _CONTEXT_H 9 | 10 | #include "context_self.h" 11 | 12 | void add_context_tests(void); 13 | void context_tests_cleanup(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /selftest/context_self.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4 | * 5 | * context_self.h: The data structure passed between user level and kernel for the 6 | * hybrid self tests. Included both from user space and kernel space and 7 | * needs to be a C struct. 8 | */ 9 | 10 | #ifndef KTF_CONTEXT_SELF_H 11 | #define KTF_CONTEXT_SELF_H 12 | 13 | #define CONTEXT_SELF_MAX_TEXT 30 14 | 15 | /* A simple example parameter block: 16 | * For verification purposes it can be useful to have a field 17 | * like 'magic' below, which serves for the purpose of 18 | * a sanity check that the parameters sent by the user program 19 | * actually corresponds to what the kernel expects: 20 | */ 21 | struct test_parameter_block { 22 | long magic; 23 | long myvalue; 24 | char s[CONTEXT_SELF_MAX_TEXT+1]; 25 | }; 26 | 27 | /* Constants for the selftest.param_context test: */ 28 | #define CONTEXT_MSG "from user to kernel" 29 | #define CONTEXT_MAGIC1 0xfaaa1234UL 30 | #define CONTEXT_MAGIC2 0xaabbccUL 31 | #define CONTEXT_MAGIC3 0x123456UL 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /selftest/hybrid.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 4 | * 5 | * hybrid.c: Hybrid (combined user level and kernel) self tests, kernel side 6 | */ 7 | 8 | #include "ktf.h" 9 | #include "hybrid.h" 10 | 11 | /* First a simple message passing test that just verifies that we receive 12 | * "out-of-band" data from user space: 13 | */ 14 | 15 | TEST(selftest, msg) 16 | { 17 | /* Accept data of type 'struct hybrid_self_params' (defined in hybrid_self.h) 18 | * from user mode. This functionality is to allow user mode to test something, 19 | * for instance that a certain parameter is handled in a specific way in the kernel. 20 | * The user then has the option to provide data to the kernel out-of-band to 21 | * tell the kernel side what to expect. 22 | * In this test, just verify that data has been transmitted correctly: 23 | */ 24 | KTF_USERDATA(self, hybrid_self_params, data); 25 | 26 | EXPECT_STREQ(data->text_val, HYBRID_MSG); 27 | EXPECT_LONG_EQ(data->val, HYBRID_MSG_VAL); 28 | } 29 | 30 | void add_hybrid_tests(void) 31 | { 32 | ADD_TEST(msg); 33 | } 34 | -------------------------------------------------------------------------------- /selftest/hybrid.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 4 | * 5 | * hybrid.h: Hybrid (combined user level and kernel) self tests, 6 | * kernel side, internal interface: 7 | */ 8 | 9 | #ifndef KTF_HYBRID_H 10 | #define KTF_HYBRID_H 11 | 12 | #include "hybrid_self.h" 13 | 14 | /* The kernel part of hybrid tests must be added to KTFs set of tests like any other tests, 15 | * in fact from KTF's kernel perspective it is like any other test, except that it likely will 16 | * fail if called without the context provided from the user space side. 17 | * 18 | * This function adds the tests declared in hybrid.c 19 | */ 20 | void add_hybrid_tests(void); 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /selftest/hybrid_self.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 4 | * 5 | * hybrid_self.h: The data structure passed between user level and kernel for the 6 | * hybrid self tests. Included both from user space and kernel space and 7 | * needs to be a C struct. 8 | */ 9 | 10 | #ifndef KTF_HYBRID_SELF_H 11 | #define KTF_HYBRID_SELF_H 12 | 13 | #define HYBRID_SELF_MAX_TEXT 127 14 | 15 | struct hybrid_self_params 16 | { 17 | char text_val[HYBRID_SELF_MAX_TEXT+1]; 18 | unsigned long val; 19 | }; 20 | 21 | 22 | /* Constants for the selftest.msg test: */ 23 | #define HYBRID_MSG "a little test string" 24 | #define HYBRID_MSG_VAL 0xffUL 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /selftest/ktf_syms.txt: -------------------------------------------------------------------------------- 1 | #module ktf 2 | #header ktf_map.h 3 | ktf_map_init 4 | ktf_map_elem_init 5 | ktf_map_insert 6 | ktf_map_find 7 | ktf_map_find_first 8 | ktf_map_remove 9 | ktf_map_elem_get 10 | ktf_map_elem_put 11 | ktf_map_find_next 12 | ktf_map_delete_all 13 | #header ktf_cov.h 14 | ktf_cov_entry_find 15 | ktf_cov_entry_put 16 | ktf_cov_enable 17 | ktf_cov_disable 18 | -------------------------------------------------------------------------------- /selftest/runchecks.cfg: -------------------------------------------------------------------------------- 1 | 2 | checker checkpatch 3 | 4 | # Older kernels fail on the SPDX license tag which now uses //: 5 | pervasive C99_COMMENTS 6 | 7 | # The use of printk here is the whole purpose of a test: 8 | except PREFER_PR_LEVEL self.c 9 | 10 | checker sparse 11 | 12 | # No good way to resolve all these without adding burden to test writers: 13 | pervasive DECL 14 | 15 | # sparse produce errors for this from slab.h in 4.20: 16 | except DUBIOUS_EXPR self.c context.c 17 | -------------------------------------------------------------------------------- /user/Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | 3 | ACLOCAL_AMFLAGS = -I m4 4 | 5 | AM_CFLAGS = -I$(top_srcdir)/lib $(NETLINK_CFLAGS) $(KTF_CFLAGS) \ 6 | -Wall -Werror \ 7 | -Wno-packed-bitfield-compat -D_GNU_SOURCE 8 | 9 | AM_CXXFLAGS = -I$(top_srcdir)/lib $(NETLINK_CFLAGS) $(KTF_CXXFLAGS) \ 10 | -Wall \ 11 | -Wno-packed-bitfield-compat \ 12 | -Wno-pointer-arith -Werror \ 13 | -D__FILENAME__=\"`basename $<`\" 14 | LDADD = -L$(top_builddir)/lib -lktf $(NETLINK_LIBS) $(KTF_LIBS) 15 | 16 | bin_PROGRAMS = ktfrun ktfcov ktftest 17 | 18 | ## Simple kernel test runner sample program: 19 | ktfrun_SOURCES = ktfrun.cpp 20 | ktfcov_SOURCES = ktfcov.cpp 21 | 22 | ## Configure and run the KTF selftests: 23 | ktftest_SOURCES = ktftest.cpp hybrid.cpp 24 | -------------------------------------------------------------------------------- /user/hybrid.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * hybrid.cpp: User mode part of the hybrid_self 7 | * test in selftests 8 | */ 9 | 10 | #include "ktf.h" 11 | #include 12 | 13 | extern "C" { 14 | #include "../selftest/hybrid_self.h" 15 | } 16 | 17 | /* User side of a simple hybrid test that just sends an out-of-band message 18 | * to the kernel side - the kernel implementation picks it up and verifies 19 | * that it is the expected string and integer values. 20 | * 21 | * This form of test allows the mixing of normal gtest user land assertions 22 | * with one or more calls to the kernel side to run tests there: 23 | */ 24 | 25 | HTEST(selftest, msg) 26 | { 27 | KTF_USERDATA(self, hybrid_self_params, data); 28 | 29 | strcpy(data->text_val, HYBRID_MSG); 30 | data->val = HYBRID_MSG_VAL; 31 | 32 | /* assertions can be specified here: */ 33 | EXPECT_TRUE(true); 34 | 35 | ktf::run(self); 36 | 37 | /* and here.. */ 38 | EXPECT_TRUE(true); 39 | } 40 | -------------------------------------------------------------------------------- /user/ktfcov.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Alan Maguire 5 | * 6 | * ktfcov.cpp: 7 | * User level application to enable/disable coverage of kernel modules. 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "ktf.h" 14 | #include "../kernel/ktf_unlproto.h" 15 | 16 | using namespace std; 17 | 18 | void 19 | usage(char *progname) 20 | { 21 | cerr << "Usage: " << progname << " [-e module[-m]] [-d module]\n"; 22 | } 23 | 24 | int main (int argc, char** argv) 25 | { 26 | int opt, nopts = 0; 27 | unsigned int cov_opts = 0; 28 | std::string modname = std::string(); 29 | bool enable = false; 30 | 31 | ktf::setup(); 32 | testing::InitGoogleTest(&argc,argv); 33 | 34 | if (argc < 3) { 35 | usage(argv[0]); 36 | return -1; 37 | } 38 | 39 | while ((opt = getopt(argc, argv, "e:d:m")) != -1) { 40 | switch (opt) { 41 | case 'e': 42 | nopts++; 43 | enable = true; 44 | modname = optarg; 45 | break; 46 | case 'd': 47 | nopts++; 48 | enable = false; 49 | modname = optarg; 50 | break; 51 | case 'm': 52 | cov_opts |= KTF_COV_OPT_MEM; 53 | break; 54 | default: 55 | cerr << "Unknown option '" << char(optopt) << "'"; 56 | return -1; 57 | } 58 | } 59 | /* Either enable or disable must be specified, and -m is only valid 60 | * for enable. 61 | */ 62 | if (modname.size() == 0 || nopts != 1 || (cov_opts && !enable)) { 63 | usage(argv[0]); 64 | return -1; 65 | } 66 | return ktf::set_coverage(modname, cov_opts, enable); 67 | } 68 | -------------------------------------------------------------------------------- /user/ktfrun.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktfrun.cpp: Generic user level application to run kernel tests 7 | * provided by modules subscribing to ktf services. 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | int main (int argc, char** argv) 14 | { 15 | ktf::setup(); 16 | testing::InitGoogleTest(&argc,argv); 17 | 18 | return RUN_ALL_TESTS(); 19 | } 20 | -------------------------------------------------------------------------------- /user/ktftest.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* 3 | * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. 4 | * Author: Knut Omang 5 | * 6 | * ktfrun.cpp: Generic user level application to run kernel tests 7 | * provided by modules subscribing to ktf services. 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | extern "C" { 14 | #include "../selftest/context_self.h" 15 | } 16 | 17 | void selftest_configure() 18 | { 19 | struct test_parameter_block p; 20 | memset(&p, 0, sizeof(p)); 21 | strcpy(p.s, CONTEXT_MSG); 22 | 23 | /* First configure two contexts provided by the kernel part: */ 24 | p.magic = CONTEXT_MAGIC1; 25 | KTF_CONTEXT_CFG("context1", "context_type_1", test_parameter_block, &p); 26 | p.magic = CONTEXT_MAGIC2; 27 | KTF_CONTEXT_CFG("context2", "context_type_2", test_parameter_block, &p); 28 | 29 | /* Configure a 3rd, dynamically created context, using CONTEXT3_TYPE_ID 30 | * which the kernel part has enabled for dynamic creation of contexts 31 | * from user space (see kernel/context.c: add_context_tests() 32 | * for details of setup) 33 | */ 34 | p.magic = CONTEXT_MAGIC3; 35 | KTF_CONTEXT_CFG("context3", "context_type_3", test_parameter_block, &p); 36 | } 37 | 38 | 39 | int main (int argc, char** argv) 40 | { 41 | ktf::setup(selftest_configure); 42 | testing::InitGoogleTest(&argc,argv); 43 | 44 | return RUN_ALL_TESTS(); 45 | } 46 | --------------------------------------------------------------------------------