mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
kgdb patches for 5.10-rc1
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. Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEELzVBU1D3lWq6cKzwfOMlXTn3iKEFAl+IdyAACgkQfOMlXTn3 iKHeTw//RDAWm0IU00z9+ZlTyksTk0vePuYKwgEm8zp+XYvY0NvpgWyZ5MWd8b3K WJmsTfXMHNoPCg3464XCrQDyIhrfhxk0nrdOpgbsQMb7HdjYrnltPdG3l8W9kvVv MjMH98QOBaYAY75nd8pGoPVTOmODrhowWo6+y4me2CnJGKOOV/yHmctBhlOJhbeo TCUIDP/NmC63N8Oziteym1TZ5dhschBb/85qEb72wXaiGEZTaVC9GEFEgCqfADHX 51KxbtZoJWirbXu2aYaK5MHEb/0NWPMItiER7y8ZrTiPHMRre4N5DpCMpKpp3/qd YRtEnNnT+Ay0ijCt2FjznSsEh2ecLI0qSO4QDQz320QJCj7qgcjJ0++yEayrzz8W IxCbwkUP8X5m1srXSxvOTKfuu29wiMCqNkJA0rgjpA2u4Yn5KO0ZRmBoHtW1Sq8E MhbRTixU/vFYosjd/mKubj/f4DFrMILo+FJTqdewBUhT/Q6Vr9l660JzvwWnKKJF e1EHNYtWo4J+EkL9z++5d9PzDl0d56DcE8rfH53Dkg075Wnma3tdq2Z7WxT3M7EP K3U32BI9obu+lPHxl4FtAobCIDjP6NtmmMo3zzzA1fPtXNzAjy7qZ+Ss6POQppkn 7v+PFYdFJ8VKo3PNxMWnFhgwSDOYYxCPjCxs+bjaMBvHNVgg2Ig= =x91W -----END PGP SIGNATURE----- Merge tag 'kgdb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux 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
This commit is contained in:
commit
49dc6fbce3
@ -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() \
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -147,7 +147,6 @@ int kdb_stub(struct kgdb_state *ks)
|
||||
return DBG_PASS_EVENT;
|
||||
}
|
||||
kdb_bp_install(ks->linux_regs);
|
||||
dbg_activate_sw_breakpoints();
|
||||
/* Set the exit state to a single step or a continue */
|
||||
if (KDB_STATE(DOING_SS))
|
||||
gdbstub_state(ks, "s");
|
||||
@ -167,7 +166,6 @@ int kdb_stub(struct kgdb_state *ks)
|
||||
* differently vs the gdbstub
|
||||
*/
|
||||
kgdb_single_step = 0;
|
||||
dbg_deactivate_sw_breakpoints();
|
||||
return DBG_SWITCH_CPU_EVENT;
|
||||
}
|
||||
return kgdb_info[ks->cpu].ret_state;
|
||||
|
@ -545,18 +545,18 @@ static int kdb_search_string(char *searched, char *searchfor)
|
||||
static void kdb_msg_write(const char *msg, int msg_len)
|
||||
{
|
||||
struct console *c;
|
||||
const char *cp;
|
||||
int len;
|
||||
|
||||
if (msg_len == 0)
|
||||
return;
|
||||
|
||||
if (dbg_io_ops) {
|
||||
const char *cp = msg;
|
||||
int len = msg_len;
|
||||
cp = msg;
|
||||
len = msg_len;
|
||||
|
||||
while (len--) {
|
||||
dbg_io_ops->write_char(*cp);
|
||||
cp++;
|
||||
}
|
||||
while (len--) {
|
||||
dbg_io_ops->write_char(*cp);
|
||||
cp++;
|
||||
}
|
||||
|
||||
for_each_console(c) {
|
||||
@ -706,12 +706,16 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap)
|
||||
size_avail = sizeof(kdb_buffer) - len;
|
||||
goto kdb_print_out;
|
||||
}
|
||||
if (kdb_grepping_flag >= KDB_GREPPING_FLAG_SEARCH)
|
||||
if (kdb_grepping_flag >= KDB_GREPPING_FLAG_SEARCH) {
|
||||
/*
|
||||
* This was a interactive search (using '/' at more
|
||||
* prompt) and it has completed. Clear the flag.
|
||||
* prompt) and it has completed. Replace the \0 with
|
||||
* its original value to ensure multi-line strings
|
||||
* are handled properly, and return to normal mode.
|
||||
*/
|
||||
*cphold = replaced_byte;
|
||||
kdb_grepping_flag = 0;
|
||||
}
|
||||
/*
|
||||
* at this point the string is a full line and
|
||||
* should be printed, up to the null.
|
||||
|
@ -2299,10 +2299,10 @@ void kdb_ps_suppressed(void)
|
||||
if (kdb_task_state(p, mask_I))
|
||||
++idle;
|
||||
}
|
||||
kdb_do_each_thread(g, p) {
|
||||
for_each_process_thread(g, p) {
|
||||
if (kdb_task_state(p, mask_M))
|
||||
++daemon;
|
||||
} kdb_while_each_thread(g, p);
|
||||
}
|
||||
if (idle || daemon) {
|
||||
if (idle)
|
||||
kdb_printf("%d idle process%s (state I)%s\n",
|
||||
@ -2370,12 +2370,12 @@ static int kdb_ps(int argc, const char **argv)
|
||||
}
|
||||
kdb_printf("\n");
|
||||
/* Now the real tasks */
|
||||
kdb_do_each_thread(g, p) {
|
||||
for_each_process_thread(g, p) {
|
||||
if (KDB_FLAG(CMD_INTERRUPT))
|
||||
return 0;
|
||||
if (kdb_task_state(p, mask))
|
||||
kdb_ps1(p);
|
||||
} kdb_while_each_thread(g, p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -230,10 +230,6 @@ extern struct task_struct *kdb_curr_task(int);
|
||||
|
||||
#define kdb_task_has_cpu(p) (task_curr(p))
|
||||
|
||||
/* Simplify coexistence with NPTL */
|
||||
#define kdb_do_each_thread(g, p) do_each_thread(g, p)
|
||||
#define kdb_while_each_thread(g, p) while_each_thread(g, p)
|
||||
|
||||
#define GFP_KDB (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
|
||||
|
||||
extern void *debug_kmalloc(size_t size, gfp_t flags);
|
||||
|
@ -24,6 +24,21 @@ menuconfig KGDB
|
||||
|
||||
if KGDB
|
||||
|
||||
config KGDB_HONOUR_BLOCKLIST
|
||||
bool "KGDB: use kprobe blocklist to prohibit unsafe breakpoints"
|
||||
depends on HAVE_KPROBES
|
||||
depends on MODULES
|
||||
select KPROBES
|
||||
default y
|
||||
help
|
||||
If set to Y the debug core will use the kprobe blocklist to
|
||||
identify symbols where it is unsafe to set breakpoints.
|
||||
In particular this disallows instrumentation of functions
|
||||
called during debug trap handling and thus makes it very
|
||||
difficult to inadvertently provoke recursive trap handling.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config KGDB_SERIAL_CONSOLE
|
||||
tristate "KGDB: use kgdb over the serial console"
|
||||
select CONSOLE_POLL
|
||||
|
Loading…
Reference in New Issue
Block a user