Skip to content

Commit

Permalink
Merge tag 'kgdb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/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
  • Loading branch information
torvalds committed Oct 16, 2020
2 parents 09a31a7 + d081a6e commit 49dc6fb
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 34 deletions.
18 changes: 18 additions & 0 deletions include/linux/kgdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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() \
Expand Down
48 changes: 38 additions & 10 deletions kernel/debug/debug_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand Down Expand Up @@ -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)
{
Expand All @@ -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
Expand All @@ -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)
{
Expand All @@ -218,6 +217,7 @@ int __weak kgdb_skipexception(int exception, struct pt_regs *regs)
{
return 0;
}
NOKPROBE_SYMBOL(kgdb_skipexception);

#ifdef CONFIG_SMP

Expand All @@ -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)
{
Expand Down Expand Up @@ -272,6 +273,7 @@ void __weak kgdb_roundup_cpus(void)
kgdb_info[cpu].rounding_up = false;
}
}
NOKPROBE_SYMBOL(kgdb_roundup_cpus);

#endif

Expand All @@ -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:
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -556,13 +562,15 @@ static int kgdb_reenter_check(struct kgdb_state *ks)

return 1;
}
NOKPROBE_SYMBOL(kgdb_reenter_check);

static void dbg_touch_watchdogs(void)
{
touch_softlockup_watchdog_sync();
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)
Expand Down Expand Up @@ -752,6 +760,8 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
}
}

dbg_activate_sw_breakpoints();

/* Call the I/O driver's post_exception routine */
if (dbg_io_ops->post_exception)
dbg_io_ops->post_exception();
Expand Down Expand Up @@ -794,6 +804,7 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,

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

/*
* kgdb_handle_exception() - main entry point from a kernel exception
Expand Down Expand Up @@ -838,6 +849,7 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
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.
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
{
Expand Down
5 changes: 2 additions & 3 deletions kernel/debug/gdbstub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -735,7 +735,7 @@ static void gdb_cmd_query(struct kgdb_state *ks)
finished = 1;
}
i++;
} while_each_thread(g, p);
}

*(--ptr) = '\0';
break;
Expand Down Expand Up @@ -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:
Expand Down
9 changes: 9 additions & 0 deletions kernel/debug/kdb/kdb_bp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
4 changes: 2 additions & 2 deletions kernel/debug/kdb/kdb_bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions kernel/debug/kdb/kdb_debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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;
Expand Down
22 changes: 13 additions & 9 deletions kernel/debug/kdb/kdb_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions kernel/debug/kdb/kdb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 0 additions & 4 deletions kernel/debug/kdb/kdb_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 49dc6fb

Please sign in to comment.