linux/drivers/misc/kgdbts.c

// 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();