Commit 49dc6fbc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull kgdb updates from Daniel Thompson:
 "A fairly modest set of changes for this cycle.

  Of particular note are an earlycon fix from Doug Anderson and my own
  changes to get kgdb/kdb to honour the kprobe blocklist. The later
  creates a safety rail that strongly encourages developers not to place
  breakpoints in, for example, arch specific trap handling code.

  Also included are a couple of small fixes and tweaks: an API update,
  eliminate a coverity dead code warning, improved handling of search
  during multi-line printk and a couple of typo corrections"

* tag 'kgdb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux:
  kdb: Fix pager search for multi-line strings
  kernel: debug: Centralize dbg_[de]activate_sw_breakpoints
  kgdb: Add NOKPROBE labels on the trap handler functions
  kgdb: Honour the kprobe blocklist when setting breakpoints
  kernel/debug: Fix spelling mistake in debug_core.c
  kdb: Use newer api for tasklist scanning
  kgdb: Make "kgdbcon" work properly with "kgdb_earlycon"
  kdb: remove unnecessary null check of dbg_io_ops
parents 09a31a7e d081a6e3
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/atomic.h>
#include <linux/kprobes.h>
#ifdef CONFIG_HAVE_ARCH_KGDB
#include <asm/kgdb.h>
#endif
@@ -335,6 +336,23 @@ extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code,
			  atomic_t *snd_rdy);
extern void gdbstub_exit(int status);

/*
 * kgdb and kprobes both use the same (kprobe) blocklist (which makes sense
 * given they are both typically hooked up to the same trap meaning on most
 * architectures one cannot be used to debug the other)
 *
 * However on architectures where kprobes is not (yet) implemented we permit
 * breakpoints everywhere rather than blocking everything by default.
 */
static inline bool kgdb_within_blocklist(unsigned long addr)
{
#ifdef CONFIG_KGDB_HONOUR_BLOCKLIST
	return within_kprobe_blacklist(addr);
#else
	return false;
#endif
}

extern int			kgdb_single_step;
extern atomic_t			kgdb_active;
#define in_dbg_master() \
+38 −10
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ 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 */
/* Action for the reboot notifier, a global allow kdb to change it */
static int kgdbreboot;
/* kgdb console driver is loaded */
static int kgdb_con_registered;
@@ -94,14 +94,6 @@ int dbg_switch_cpu;
/* Use kdb or gdbserver mode */
int dbg_kdb_mode = 1;

static int __init opt_kgdb_con(char *str)
{
	kgdb_use_con = 1;
	return 0;
}

early_param("kgdbcon", opt_kgdb_con);

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

@@ -163,7 +155,7 @@ early_param("nokgdbroundup", opt_nokgdbroundup);

/*
 * Weak aliases for breakpoint management,
 * can be overriden by architectures when needed:
 * can be overridden by architectures when needed:
 */
int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
{
@@ -177,17 +169,23 @@ int __weak kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
				 arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE);
	return err;
}
NOKPROBE_SYMBOL(kgdb_arch_set_breakpoint);

int __weak kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
{
	return copy_to_kernel_nofault((char *)bpt->bpt_addr,
				  (char *)bpt->saved_instr, BREAK_INSTR_SIZE);
}
NOKPROBE_SYMBOL(kgdb_arch_remove_breakpoint);

int __weak kgdb_validate_break_address(unsigned long addr)
{
	struct kgdb_bkpt tmp;
	int err;

	if (kgdb_within_blocklist(addr))
		return -EINVAL;

	/* Validate setting the breakpoint and then removing it.  If the
	 * remove fails, the kernel needs to emit a bad message because we
	 * are deep trouble not being able to put things back the way we
@@ -208,6 +206,7 @@ unsigned long __weak kgdb_arch_pc(int exception, struct pt_regs *regs)
{
	return instruction_pointer(regs);
}
NOKPROBE_SYMBOL(kgdb_arch_pc);

int __weak kgdb_arch_init(void)
{
@@ -218,6 +217,7 @@ int __weak kgdb_skipexception(int exception, struct pt_regs *regs)
{
	return 0;
}
NOKPROBE_SYMBOL(kgdb_skipexception);

#ifdef CONFIG_SMP

@@ -239,6 +239,7 @@ void __weak kgdb_call_nmi_hook(void *ignored)
	 */
	kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
}
NOKPROBE_SYMBOL(kgdb_call_nmi_hook);

void __weak kgdb_roundup_cpus(void)
{
@@ -272,6 +273,7 @@ void __weak kgdb_roundup_cpus(void)
			kgdb_info[cpu].rounding_up = false;
	}
}
NOKPROBE_SYMBOL(kgdb_roundup_cpus);

#endif

@@ -298,6 +300,7 @@ static void kgdb_flush_swbreak_addr(unsigned long addr)
	/* Force flush instruction cache if it was outside the mm */
	flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
}
NOKPROBE_SYMBOL(kgdb_flush_swbreak_addr);

/*
 * SW breakpoint management:
@@ -325,6 +328,7 @@ int dbg_activate_sw_breakpoints(void)
	}
	return ret;
}
NOKPROBE_SYMBOL(dbg_activate_sw_breakpoints);

int dbg_set_sw_break(unsigned long addr)
{
@@ -388,6 +392,7 @@ int dbg_deactivate_sw_breakpoints(void)
	}
	return ret;
}
NOKPROBE_SYMBOL(dbg_deactivate_sw_breakpoints);

int dbg_remove_sw_break(unsigned long addr)
{
@@ -509,6 +514,7 @@ static int kgdb_io_ready(int print_wait)
	}
	return 1;
}
NOKPROBE_SYMBOL(kgdb_io_ready);

static int kgdb_reenter_check(struct kgdb_state *ks)
{
@@ -556,6 +562,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks)

	return 1;
}
NOKPROBE_SYMBOL(kgdb_reenter_check);

static void dbg_touch_watchdogs(void)
{
@@ -563,6 +570,7 @@ static void dbg_touch_watchdogs(void)
	clocksource_touch_watchdog();
	rcu_cpu_stall_reset();
}
NOKPROBE_SYMBOL(dbg_touch_watchdogs);

static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
		int exception_state)
@@ -752,6 +760,8 @@ cpu_master_loop:
		}
	}

	dbg_activate_sw_breakpoints();

	/* Call the I/O driver's post_exception routine */
	if (dbg_io_ops->post_exception)
		dbg_io_ops->post_exception();
@@ -794,6 +804,7 @@ kgdb_restore:

	return kgdb_info[cpu].ret_state;
}
NOKPROBE_SYMBOL(kgdb_cpu_enter);

/*
 * kgdb_handle_exception() - main entry point from a kernel exception
@@ -838,6 +849,7 @@ out:
		arch_kgdb_ops.enable_nmi(1);
	return ret;
}
NOKPROBE_SYMBOL(kgdb_handle_exception);

/*
 * GDB places a breakpoint at this function to know dynamically loaded objects.
@@ -872,6 +884,7 @@ int kgdb_nmicallback(int cpu, void *regs)
#endif
	return 1;
}
NOKPROBE_SYMBOL(kgdb_nmicallback);

int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code,
							atomic_t *send_ready)
@@ -897,6 +910,7 @@ int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code,
#endif
	return 1;
}
NOKPROBE_SYMBOL(kgdb_nmicallin);

static void kgdb_console_write(struct console *co, const char *s,
   unsigned count)
@@ -920,6 +934,20 @@ static struct console kgdbcons = {
	.index		= -1,
};

static int __init opt_kgdb_con(char *str)
{
	kgdb_use_con = 1;

	if (kgdb_io_module_registered && !kgdb_con_registered) {
		register_console(&kgdbcons);
		kgdb_con_registered = 1;
	}

	return 0;
}

early_param("kgdbcon", opt_kgdb_con);

#ifdef CONFIG_MAGIC_SYSRQ
static void sysrq_handle_dbg(int key)
{
+2 −3
Original line number Diff line number Diff line
@@ -725,7 +725,7 @@ static void gdb_cmd_query(struct kgdb_state *ks)
			}
		}

		do_each_thread(g, p) {
		for_each_process_thread(g, p) {
			if (i >= ks->thr_query && !finished) {
				int_to_threadref(thref, p->pid);
				ptr = pack_threadid(ptr, thref);
@@ -735,7 +735,7 @@ static void gdb_cmd_query(struct kgdb_state *ks)
					finished = 1;
			}
			i++;
		} while_each_thread(g, p);
		}

		*(--ptr) = '\0';
		break;
@@ -1061,7 +1061,6 @@ int gdb_serial_stub(struct kgdb_state *ks)
				error_packet(remcom_out_buffer, -EINVAL);
				break;
			}
			dbg_activate_sw_breakpoints();
			fallthrough;	/* to default processing */
		default:
default_handle:
+9 −0
Original line number Diff line number Diff line
@@ -306,6 +306,15 @@ static int kdb_bp(int argc, const char **argv)
	if (!template.bp_addr)
		return KDB_BADINT;

	/*
	 * This check is redundant (since the breakpoint machinery should
	 * be doing the same check during kdb_bp_install) but gives the
	 * user immediate feedback.
	 */
	diag = kgdb_validate_break_address(template.bp_addr);
	if (diag)
		return diag;

	/*
	 * Find an empty bp structure to allocate
	 */
+2 −2
Original line number Diff line number Diff line
@@ -149,14 +149,14 @@ kdb_bt(int argc, const char **argv)
				return 0;
		}
		/* Now the inactive tasks */
		kdb_do_each_thread(g, p) {
		for_each_process_thread(g, p) {
			if (KDB_FLAG(CMD_INTERRUPT))
				return 0;
			if (task_curr(p))
				continue;
			if (kdb_bt1(p, mask, btaprompt))
				return 0;
		} kdb_while_each_thread(g, p);
		}
	} else if (strcmp(argv[0], "btp") == 0) {
		struct task_struct *p;
		unsigned long pid;
Loading