Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a20ae85a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull KGDB/KDB updates from Jason Wessel:
 "Fixes:
   - Fix KDB keyboard repeat scan codes and leaked keyboard events
   - Fix kernel crash with kdb_printf() for users who compile new
     kdb_printf()'s in early code
   - Return all segment registers to gdb on x86_64

  Features:
   - KDB/KGDB hook the reboot notifier and end user can control if it
     stops, detaches or does nothing (updated docs as well)
   - Notify users who use CONFIG_DEBUG_RODATA to use hw breakpoints"

* tag 'for_linus-3.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb:
  kdb: Add message about CONFIG_DEBUG_RODATA on failure to install breakpoint
  kdb: Avoid using dbg_io_ops until it is initialized
  kgdb,debug_core: add the ability to control the reboot notifier
  KDB: Fix usability issues relating to the 'enter' key.
  kgdb,debug-core,gdbstub: Hook the reboot notifier for debugger detach
  kgdb: Respect that flush op is optional
  kgdb: x86: Return all segment registers also in 64-bit mode
parents f0a5ec0e 1ba0c172
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -361,6 +361,23 @@
   <para>It is possible to use this option with kgdboc on a tty that is not a system console.
   </para>
  </para>
  </sect1>
   <sect1 id="kgdbreboot">
   <title>Run time parameter: kgdbreboot</title>
   <para> The kgdbreboot feature allows you to change how the debugger
   deals with the reboot notification.  You have 3 choices for the
   behavior.  The default behavior is always set to 0.</para>
   <orderedlist>
   <listitem><para>echo -1 > /sys/module/debug_core/parameters/kgdbreboot</para>
   <para>Ignore the reboot notification entirely.</para>
   </listitem>
   <listitem><para>echo 0 > /sys/module/debug_core/parameters/kgdbreboot</para>
   <para>Send the detach message to any attached debugger client.</para>
   </listitem>
   <listitem><para>echo 1 > /sys/module/debug_core/parameters/kgdbreboot</para>
   <para>Enter the debugger on reboot notify.</para>
   </listitem>
   </orderedlist>
  </sect1>
  </chapter>
  <chapter id="usingKDB">
+7 −3
Original line number Diff line number Diff line
@@ -64,11 +64,15 @@ enum regnames {
	GDB_PS,			/* 17 */
	GDB_CS,			/* 18 */
	GDB_SS,			/* 19 */
	GDB_DS,			/* 20 */
	GDB_ES,			/* 21 */
	GDB_FS,			/* 22 */
	GDB_GS,			/* 23 */
};
#define GDB_ORIG_AX		57
#define DBG_MAX_REG_NUM		20
/* 17 64 bit regs and 3 32 bit regs */
#define NUMREGBYTES		((17 * 8) + (3 * 4))
#define DBG_MAX_REG_NUM		24
/* 17 64 bit regs and 5 32 bit regs */
#define NUMREGBYTES		((17 * 8) + (5 * 4))
#endif /* ! CONFIG_X86_32 */

static inline void arch_kgdb_breakpoint(void)
+4 −2
Original line number Diff line number Diff line
@@ -67,8 +67,6 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
	{ "ss", 4, offsetof(struct pt_regs, ss) },
	{ "ds", 4, offsetof(struct pt_regs, ds) },
	{ "es", 4, offsetof(struct pt_regs, es) },
	{ "fs", 4, -1 },
	{ "gs", 4, -1 },
#else
	{ "ax", 8, offsetof(struct pt_regs, ax) },
	{ "bx", 8, offsetof(struct pt_regs, bx) },
@@ -90,7 +88,11 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
	{ "flags", 4, offsetof(struct pt_regs, flags) },
	{ "cs", 4, offsetof(struct pt_regs, cs) },
	{ "ss", 4, offsetof(struct pt_regs, ss) },
	{ "ds", 4, -1 },
	{ "es", 4, -1 },
#endif
	{ "fs", 4, -1 },
	{ "gs", 4, -1 },
};

int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+33 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/sysrq.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/kgdb.h>
#include <linux/kdb.h>
@@ -75,6 +76,8 @@ static int exception_level;
struct kgdb_io		*dbg_io_ops;
static DEFINE_SPINLOCK(kgdb_registration_lock);

/* Action for the reboot notifiter, a global allow kdb to change it */
static int kgdbreboot;
/* kgdb console driver is loaded */
static int kgdb_con_registered;
/* determine if kgdb console output should be used */
@@ -96,6 +99,7 @@ static int __init opt_kgdb_con(char *str)
early_param("kgdbcon", opt_kgdb_con);

module_param(kgdb_use_con, int, 0644);
module_param(kgdbreboot, int, 0644);

/*
 * Holds information about breakpoints in a kernel. These breakpoints are
@@ -784,6 +788,33 @@ void __init dbg_late_init(void)
	kdb_init(KDB_INIT_FULL);
}

static int
dbg_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
{
	/*
	 * Take the following action on reboot notify depending on value:
	 *    1 == Enter debugger
	 *    0 == [the default] detatch debug client
	 *   -1 == Do nothing... and use this until the board resets
	 */
	switch (kgdbreboot) {
	case 1:
		kgdb_breakpoint();
	case -1:
		goto done;
	}
	if (!dbg_kdb_mode)
		gdbstub_exit(code);
done:
	return NOTIFY_DONE;
}

static struct notifier_block dbg_reboot_notifier = {
	.notifier_call		= dbg_notify_reboot,
	.next			= NULL,
	.priority		= INT_MAX,
};

static void kgdb_register_callbacks(void)
{
	if (!kgdb_io_module_registered) {
@@ -791,6 +822,7 @@ static void kgdb_register_callbacks(void)
		kgdb_arch_init();
		if (!dbg_is_early)
			kgdb_arch_late();
		register_reboot_notifier(&dbg_reboot_notifier);
		atomic_notifier_chain_register(&panic_notifier_list,
					       &kgdb_panic_event_nb);
#ifdef CONFIG_MAGIC_SYSRQ
@@ -812,6 +844,7 @@ static void kgdb_unregister_callbacks(void)
	 */
	if (kgdb_io_module_registered) {
		kgdb_io_module_registered = 0;
		unregister_reboot_notifier(&dbg_reboot_notifier);
		atomic_notifier_chain_unregister(&panic_notifier_list,
					       &kgdb_panic_event_nb);
		kgdb_arch_exit();
+9 −1
Original line number Diff line number Diff line
@@ -1111,6 +1111,13 @@ void gdbstub_exit(int status)
	unsigned char checksum, ch, buffer[3];
	int loop;

	if (!kgdb_connected)
		return;
	kgdb_connected = 0;

	if (!dbg_io_ops || dbg_kdb_mode)
		return;

	buffer[0] = 'W';
	buffer[1] = hex_asc_hi(status);
	buffer[2] = hex_asc_lo(status);
@@ -1129,5 +1136,6 @@ void gdbstub_exit(int status)
	dbg_io_ops->write_char(hex_asc_lo(checksum));

	/* make sure the output is flushed, lest the bootloader clobber it */
	if (dbg_io_ops->flush)
		dbg_io_ops->flush();
}
Loading