// SPDX-License-Identifier: GPL-2.0-only /* * kgdbts is a test suite for kgdb for the sole purpose of validating * that key pieces of the kgdb internals are working properly such as * HW/SW breakpoints, single stepping, and NMI. * * Created by: Jason Wessel <[email protected]> * * Copyright (c) 2008 Wind River Systems, Inc. */ /* Information about the kgdb test suite. * ------------------------------------- * * The kgdb test suite is designed as a KGDB I/O module which * simulates the communications that a debugger would have with kgdb. * The tests are broken up in to a line by line and referenced here as * a "get" which is kgdb requesting input and "put" which is kgdb * sending a response. * * The kgdb suite can be invoked from the kernel command line * arguments system or executed dynamically at run time. The test * suite uses the variable "kgdbts" to obtain the information about * which tests to run and to configure the verbosity level. The * following are the various characters you can use with the kgdbts= * line: * * When using the "kgdbts=" you only choose one of the following core * test types: * A = Run all the core tests silently * V1 = Run all the core tests with minimal output * V2 = Run all the core tests in debug mode * * You can also specify optional tests: * N## = Go to sleep with interrupts of for ## seconds * to test the HW NMI watchdog * F## = Break at kernel_clone for ## iterations * S## = Break at sys_open for ## iterations * I## = Run the single step test ## iterations * * NOTE: that the kernel_clone and sys_open tests are mutually exclusive. * * To invoke the kgdb test suite from boot you use a kernel start * argument as follows: * kgdbts=V1 kgdbwait * Or if you wanted to perform the NMI test for 6 seconds and kernel_clone * test for 100 forks, you could use: * kgdbts=V1N6F100 kgdbwait * * The test suite can also be invoked at run time with: * echo kgdbts=V1N6F100 > /sys/module/kgdbts/parameters/kgdbts * Or as another example: * echo kgdbts=V2 > /sys/module/kgdbts/parameters/kgdbts * * When developing a new kgdb arch specific implementation or * using these tests for the purpose of regression testing, * several invocations are required. * * 1) Boot with the test suite enabled by using the kernel arguments * "kgdbts=V1F100 kgdbwait" * ## If kgdb arch specific implementation has NMI use * "kgdbts=V1N6F100 * * 2) After the system boot run the basic test. * echo kgdbts=V1 > /sys/module/kgdbts/parameters/kgdbts * * 3) Run the concurrency tests. It is best to use n+1 * while loops where n is the number of cpus you have * in your system. The example below uses only two * loops. * * ## This tests break points on sys_open * while [ 1 ] ; do find / > /dev/null 2>&1 ; done & * while [ 1 ] ; do find / > /dev/null 2>&1 ; done & * echo kgdbts=V1S10000 > /sys/module/kgdbts/parameters/kgdbts * fg # and hit control-c * fg # and hit control-c * ## This tests break points on kernel_clone * while [ 1 ] ; do date > /dev/null ; done & * while [ 1 ] ; do date > /dev/null ; done & * echo kgdbts=V1F1000 > /sys/module/kgdbts/parameters/kgdbts * fg # and hit control-c * */ #include <linux/kernel.h> #include <linux/kgdb.h> #include <linux/ctype.h> #include <linux/uaccess.h> #include <linux/syscalls.h> #include <linux/nmi.h> #include <linux/delay.h> #include <linux/kthread.h> #include <linux/module.h> #include <linux/sched/task.h> #include <linux/kallsyms.h> #include <asm/sections.h> #define v1printk(a...) … #define v2printk(a...) … #define eprintk(a...) … #define MAX_CONFIG_LEN … static struct kgdb_io kgdbts_io_ops; static char get_buf[BUFMAX]; static int get_buf_cnt; static char put_buf[BUFMAX]; static int put_buf_cnt; static char scratch_buf[BUFMAX]; static int verbose; static int repeat_test; static int test_complete; static int send_ack; static int final_ack; static int force_hwbrks; static int hwbreaks_ok; static int hw_break_val; static int hw_break_val2; static int cont_instead_of_sstep; static unsigned long cont_thread_id; static unsigned long sstep_thread_id; #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC) static int arch_needs_sstep_emulation = 1; #else static int arch_needs_sstep_emulation; #endif static unsigned long cont_addr; static unsigned long sstep_addr; static int restart_from_top_after_write; static int sstep_state; /* Storage for the registers, in GDB format. */ static unsigned long kgdbts_gdb_regs[(NUMREGBYTES + sizeof(unsigned long) - 1) / sizeof(unsigned long)]; static struct pt_regs kgdbts_regs; /* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ static int configured = …; #ifdef CONFIG_KGDB_TESTS_BOOT_STRING static char config[MAX_CONFIG_LEN] = …; #else static char config[MAX_CONFIG_LEN]; #endif static struct kparam_string kps = …; static void fill_get_buf(char *buf); struct test_struct { … }; struct test_state { … }; static struct test_state ts; static int kgdbts_unreg_thread(void *ptr) { … } /* This is noinline such that it can be used for a single location to * place a breakpoint */ static noinline void kgdbts_break_test(void) { … } /* * This is a cached wrapper for kallsyms_lookup_name(). * * The cache is a big win for several tests. For example it more the doubles * the cycles per second during the sys_open test. This is not theoretic, * the performance improvement shows up at human scale, especially when * testing using emulators. * * Obviously neither re-entrant nor thread-safe but that is OK since it * can only be called from the debug trap (and therefore all other CPUs * are halted). */ static unsigned long lookup_addr(char *arg) { … } static void break_helper(char *bp_type, char *arg, unsigned long vaddr) { … } static void sw_break(char *arg) { … } static void sw_rem_break(char *arg) { … } static void hw_break(char *arg) { … } static void hw_rem_break(char *arg) { … } static void hw_write_break(char *arg) { … } static void hw_rem_write_break(char *arg) { … } static void hw_access_break(char *arg) { … } static void hw_rem_access_break(char *arg) { … } static void hw_break_val_access(void) { … } static void hw_break_val_write(void) { … } static int get_thread_id_continue(char *put_str, char *arg) { … } static int check_and_rewind_pc(char *put_str, char *arg) { … } static int check_single_step(char *put_str, char *arg) { … } static void write_regs(char *arg) { … } static void skip_back_repeat_test(char *arg) { … } static int got_break(char *put_str, char *arg) { … } static void get_cont_catch(char *arg) { … } static int put_cont_catch(char *put_str, char *arg) { … } static int emul_reset(char *put_str, char *arg) { … } static void emul_sstep_get(char *arg) { … } static int emul_sstep_put(char *put_str, char *arg) { … } static int final_ack_set(char *put_str, char *arg) { … } /* * Test to plant a breakpoint and detach, which should clear out the * breakpoint and restore the original instruction. */ static struct test_struct plant_and_detach_test[] = …; /* * Simple test to write in a software breakpoint, check for the * correct stop location and detach. */ static struct test_struct sw_breakpoint_test[] = …; /* * Test a known bad memory read location to test the fault handler and * read bytes 1-8 at the bad address */ static struct test_struct bad_read_test[] = …; /* * Test for hitting a breakpoint, remove it, single step, plant it * again and detach. */ static struct test_struct singlestep_break_test[] = …; /* * Test for hitting a breakpoint at kernel_clone for what ever the number * of iterations required by the variable repeat_test. */ static struct test_struct do_kernel_clone_test[] = …; /* Test for hitting a breakpoint at sys_open for what ever the number * of iterations required by the variable repeat_test. */ static struct test_struct sys_open_test[] = …; /* * Test for hitting a simple hw breakpoint */ static struct test_struct hw_breakpoint_test[] = …; /* * Test for hitting a hw write breakpoint */ static struct test_struct hw_write_break_test[] = …; /* * Test for hitting a hw access breakpoint */ static struct test_struct hw_access_break_test[] = …; /* * Test for hitting a hw access breakpoint */ static struct test_struct nmi_sleep_test[] = …; static void fill_get_buf(char *buf) { … } static int validate_simple_test(char *put_str) { … } static int run_simple_test(int is_get_char, int chr) { … } static void init_simple_test(void) { … } static void run_plant_and_detach_test(int is_early) { … } static void run_breakpoint_test(int is_hw_breakpoint) { … } static void run_hw_break_test(int is_write_test) { … } static void run_nmi_sleep_test(int nmi_sleep) { … } static void run_bad_read_test(void) { … } static void run_kernel_clone_test(void) { … } static void run_sys_open_test(void) { … } static void run_singlestep_break_test(void) { … } static void kgdbts_run_tests(void) { … } static int kgdbts_option_setup(char *opt) { … } __setup(…); static int configure_kgdbts(void) { … } static int __init init_kgdbts(void) { … } device_initcall(init_kgdbts); static int kgdbts_get_char(void) { … } static void kgdbts_put_char(u8 chr) { … } static int param_set_kgdbts_var(const char *kmessage, const struct kernel_param *kp) { … } static void kgdbts_pre_exp_handler(void) { … } static void kgdbts_post_exp_handler(void) { … } static struct kgdb_io kgdbts_io_ops = …; /* * not really modular, but the easiest way to keep compat with existing * bootargs behaviour is to continue using module_param here. */ module_param_call(…); MODULE_PARM_DESC(…) …;