linux/arch/powerpc/kernel/kgdb.c

499 lines
15 KiB
C
Raw Normal View History

/*
* PowerPC backend to the KGDB stub.
*
* 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu)
* Copyright (C) 2003 Timesys Corporation.
* Copyright (C) 2004-2006 MontaVista Software, Inc.
* PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
* PPC32 support restored by Vitaly Wool <vwool@ru.mvista.com> and
* Sergei Shtylyov <sshtylyov@ru.mvista.com>
* Copyright (C) 2007-2008 Wind River Systems, Inc.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program as licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/kgdb.h>
#include <linux/smp.h>
#include <linux/signal.h>
#include <linux/ptrace.h>
#include <linux/kdebug.h>
#include <asm/current.h>
#include <asm/processor.h>
#include <asm/machdep.h>
#include <asm/debug.h>
powerpc/kgdb: add kgdb_arch_set/remove_breakpoint() Generic implementation fails to remove breakpoints after init when CONFIG_STRICT_KERNEL_RWX is selected: [ 13.251285] KGDB: BP remove failed: c001c338 [ 13.259587] kgdbts: ERROR PUT: end of test buffer on 'do_fork_test' line 8 expected OK got $E14#aa [ 13.268969] KGDB: re-enter exception: ALL breakpoints killed [ 13.275099] CPU: 0 PID: 1 Comm: init Not tainted 4.18.0-g82bbb913ffd8 #860 [ 13.282836] Call Trace: [ 13.285313] [c60e1ba0] [c0080ef0] kgdb_handle_exception+0x6f4/0x720 (unreliable) [ 13.292618] [c60e1c30] [c000e97c] kgdb_handle_breakpoint+0x3c/0x98 [ 13.298709] [c60e1c40] [c000af54] program_check_exception+0x104/0x700 [ 13.305083] [c60e1c60] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.310845] [c60e1d20] [c02a22ac] run_simple_test+0x2b4/0x2d4 [ 13.316532] [c60e1d30] [c0081698] put_packet+0xb8/0x158 [ 13.321694] [c60e1d60] [c00820b4] gdb_serial_stub+0x230/0xc4c [ 13.327374] [c60e1dc0] [c0080af8] kgdb_handle_exception+0x2fc/0x720 [ 13.333573] [c60e1e50] [c000e928] kgdb_singlestep+0xb4/0xcc [ 13.339068] [c60e1e70] [c000ae1c] single_step_exception+0x90/0xac [ 13.345100] [c60e1e80] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.350865] [c60e1f40] [c000e11c] ret_from_syscall+0x0/0x38 [ 13.356346] Kernel panic - not syncing: Recursive entry to debugger This patch creates powerpc specific version of kgdb_arch_set_breakpoint() and kgdb_arch_remove_breakpoint() using patch_instruction() Fixes: 1e0fc9d1eb2b ("powerpc/Kconfig: Enable STRICT_KERNEL_RWX for some configs") Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2018-09-18 17:26:03 +08:00
#include <asm/code-patching.h>
#include <linux/slab.h>
#include <asm/inst.h>
/*
* This table contains the mapping between PowerPC hardware trap types, and
* signals, which are primarily what GDB understands. GDB and the kernel
* don't always agree on values, so we use constants taken from gdb-6.2.
*/
static struct hard_trap_info
{
unsigned int tt; /* Trap type code for powerpc */
unsigned char signo; /* Signal that we map this trap into */
} hard_trap_info[] = {
{ 0x0100, 0x02 /* SIGINT */ }, /* system reset */
{ 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */
{ 0x0300, 0x0b /* SIGSEGV */ }, /* data access */
{ 0x0400, 0x0b /* SIGSEGV */ }, /* instruction access */
{ 0x0500, 0x02 /* SIGINT */ }, /* external interrupt */
{ 0x0600, 0x0a /* SIGBUS */ }, /* alignment */
{ 0x0700, 0x05 /* SIGTRAP */ }, /* program check */
{ 0x0800, 0x08 /* SIGFPE */ }, /* fp unavailable */
{ 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */
{ 0x0c00, 0x14 /* SIGCHLD */ }, /* system call */
#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
{ 0x2002, 0x05 /* SIGTRAP */ }, /* debug */
#if defined(CONFIG_FSL_BOOKE)
{ 0x2010, 0x08 /* SIGFPE */ }, /* spe unavailable */
{ 0x2020, 0x08 /* SIGFPE */ }, /* spe unavailable */
{ 0x2030, 0x08 /* SIGFPE */ }, /* spe fp data */
{ 0x2040, 0x08 /* SIGFPE */ }, /* spe fp data */
{ 0x2050, 0x08 /* SIGFPE */ }, /* spe fp round */
{ 0x2060, 0x0e /* SIGILL */ }, /* performance monitor */
{ 0x2900, 0x08 /* SIGFPE */ }, /* apu unavailable */
{ 0x3100, 0x0e /* SIGALRM */ }, /* fixed interval timer */
{ 0x3200, 0x02 /* SIGINT */ }, /* watchdog */
#else /* ! CONFIG_FSL_BOOKE */
{ 0x1000, 0x0e /* SIGALRM */ }, /* prog interval timer */
{ 0x1010, 0x0e /* SIGALRM */ }, /* fixed interval timer */
{ 0x1020, 0x02 /* SIGINT */ }, /* watchdog */
{ 0x2010, 0x08 /* SIGFPE */ }, /* fp unavailable */
{ 0x2020, 0x08 /* SIGFPE */ }, /* ap unavailable */
#endif
#else /* ! (defined(CONFIG_40x) || defined(CONFIG_BOOKE)) */
{ 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step */
#if defined(CONFIG_PPC_8xx)
{ 0x1000, 0x04 /* SIGILL */ }, /* software emulation */
#else /* ! CONFIG_PPC_8xx */
{ 0x0f00, 0x04 /* SIGILL */ }, /* performance monitor */
{ 0x0f20, 0x08 /* SIGFPE */ }, /* altivec unavailable */
{ 0x1300, 0x05 /* SIGTRAP */ }, /* instruction address break */
#if defined(CONFIG_PPC64)
{ 0x1200, 0x05 /* SIGILL */ }, /* system error */
{ 0x1500, 0x04 /* SIGILL */ }, /* soft patch */
{ 0x1600, 0x04 /* SIGILL */ }, /* maintenance */
{ 0x1700, 0x08 /* SIGFPE */ }, /* altivec assist */
{ 0x1800, 0x04 /* SIGILL */ }, /* thermal */
#else /* ! CONFIG_PPC64 */
{ 0x1400, 0x02 /* SIGINT */ }, /* SMI */
{ 0x1600, 0x08 /* SIGFPE */ }, /* altivec assist */
{ 0x1700, 0x04 /* SIGILL */ }, /* TAU */
{ 0x2000, 0x05 /* SIGTRAP */ }, /* run mode */
#endif
#endif
#endif
{ 0x0000, 0x00 } /* Must be last */
};
static int computeSignal(unsigned int tt)
{
struct hard_trap_info *ht;
for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
if (ht->tt == tt)
return ht->signo;
return SIGHUP; /* default for things we don't know about */
}
/**
*
* kgdb_skipexception - Bail out of KGDB when we've been triggered.
* @exception: Exception vector number
* @regs: Current &struct pt_regs.
*
* On some architectures we need to skip a breakpoint exception when
* it occurs after a breakpoint has been removed.
*
*/
int kgdb_skipexception(int exception, struct pt_regs *regs)
{
return kgdb_isremovedbreak(regs->nip);
}
kgdb: Fix kgdb_roundup_cpus() for arches who used smp_call_function() When I had lockdep turned on and dropped into kgdb I got a nice splat on my system. Specifically it hit: DEBUG_LOCKS_WARN_ON(current->hardirq_context) Specifically it looked like this: sysrq: SysRq : DEBUG ------------[ cut here ]------------ DEBUG_LOCKS_WARN_ON(current->hardirq_context) WARNING: CPU: 0 PID: 0 at .../kernel/locking/lockdep.c:2875 lockdep_hardirqs_on+0xf0/0x160 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.19.0 #27 pstate: 604003c9 (nZCv DAIF +PAN -UAO) pc : lockdep_hardirqs_on+0xf0/0x160 ... Call trace: lockdep_hardirqs_on+0xf0/0x160 trace_hardirqs_on+0x188/0x1ac kgdb_roundup_cpus+0x14/0x3c kgdb_cpu_enter+0x53c/0x5cc kgdb_handle_exception+0x180/0x1d4 kgdb_compiled_brk_fn+0x30/0x3c brk_handler+0x134/0x178 do_debug_exception+0xfc/0x178 el1_dbg+0x18/0x78 kgdb_breakpoint+0x34/0x58 sysrq_handle_dbg+0x54/0x5c __handle_sysrq+0x114/0x21c handle_sysrq+0x30/0x3c qcom_geni_serial_isr+0x2dc/0x30c ... ... irq event stamp: ...45 hardirqs last enabled at (...44): [...] __do_softirq+0xd8/0x4e4 hardirqs last disabled at (...45): [...] el1_irq+0x74/0x130 softirqs last enabled at (...42): [...] _local_bh_enable+0x2c/0x34 softirqs last disabled at (...43): [...] irq_exit+0xa8/0x100 ---[ end trace adf21f830c46e638 ]--- Looking closely at it, it seems like a really bad idea to be calling local_irq_enable() in kgdb_roundup_cpus(). If nothing else that seems like it could violate spinlock semantics and cause a deadlock. Instead, let's use a private csd alongside smp_call_function_single_async() to round up the other CPUs. Using smp_call_function_single_async() doesn't require interrupts to be enabled so we can remove the offending bit of code. In order to avoid duplicating this across all the architectures that use the default kgdb_roundup_cpus(), we'll add a "weak" implementation to debug_core.c. Looking at all the people who previously had copies of this code, there were a few variants. I've attempted to keep the variants working like they used to. Specifically: * For arch/arc we passed NULL to kgdb_nmicallback() instead of get_irq_regs(). * For arch/mips there was a bit of extra code around kgdb_nmicallback() NOTE: In this patch we will still get into trouble if we try to round up a CPU that failed to round up before. We'll try to round it up again and potentially hang when we try to grab the csd lock. That's not new behavior but we'll still try to do better in a future patch. Suggested-by: Daniel Thompson <daniel.thompson@linaro.org> Signed-off-by: Douglas Anderson <dianders@chromium.org> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Russell King <linux@armlinux.org.uk> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Richard Kuo <rkuo@codeaurora.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Paul Burton <paul.burton@mips.com> Cc: James Hogan <jhogan@kernel.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Cc: Rich Felker <dalias@libc.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
2018-12-05 11:38:26 +08:00
static int kgdb_debugger_ipi(struct pt_regs *regs)
{
kgdb_nmicallback(raw_smp_processor_id(), regs);
return 0;
}
#ifdef CONFIG_SMP
void kgdb_roundup_cpus(void)
{
smp_send_debugger_break();
}
#endif
/* KGDB functions to use existing PowerPC64 hooks. */
static int kgdb_debugger(struct pt_regs *regs)
{
return !kgdb_handle_exception(1, computeSignal(TRAP(regs)),
DIE_OOPS, regs);
}
static int kgdb_handle_breakpoint(struct pt_regs *regs)
{
if (user_mode(regs))
return 0;
if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
return 0;
powerpc/kgdb: add kgdb_arch_set/remove_breakpoint() Generic implementation fails to remove breakpoints after init when CONFIG_STRICT_KERNEL_RWX is selected: [ 13.251285] KGDB: BP remove failed: c001c338 [ 13.259587] kgdbts: ERROR PUT: end of test buffer on 'do_fork_test' line 8 expected OK got $E14#aa [ 13.268969] KGDB: re-enter exception: ALL breakpoints killed [ 13.275099] CPU: 0 PID: 1 Comm: init Not tainted 4.18.0-g82bbb913ffd8 #860 [ 13.282836] Call Trace: [ 13.285313] [c60e1ba0] [c0080ef0] kgdb_handle_exception+0x6f4/0x720 (unreliable) [ 13.292618] [c60e1c30] [c000e97c] kgdb_handle_breakpoint+0x3c/0x98 [ 13.298709] [c60e1c40] [c000af54] program_check_exception+0x104/0x700 [ 13.305083] [c60e1c60] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.310845] [c60e1d20] [c02a22ac] run_simple_test+0x2b4/0x2d4 [ 13.316532] [c60e1d30] [c0081698] put_packet+0xb8/0x158 [ 13.321694] [c60e1d60] [c00820b4] gdb_serial_stub+0x230/0xc4c [ 13.327374] [c60e1dc0] [c0080af8] kgdb_handle_exception+0x2fc/0x720 [ 13.333573] [c60e1e50] [c000e928] kgdb_singlestep+0xb4/0xcc [ 13.339068] [c60e1e70] [c000ae1c] single_step_exception+0x90/0xac [ 13.345100] [c60e1e80] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.350865] [c60e1f40] [c000e11c] ret_from_syscall+0x0/0x38 [ 13.356346] Kernel panic - not syncing: Recursive entry to debugger This patch creates powerpc specific version of kgdb_arch_set_breakpoint() and kgdb_arch_remove_breakpoint() using patch_instruction() Fixes: 1e0fc9d1eb2b ("powerpc/Kconfig: Enable STRICT_KERNEL_RWX for some configs") Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2018-09-18 17:26:03 +08:00
if (*(u32 *)regs->nip == BREAK_INSTR)
regs->nip += BREAK_INSTR_SIZE;
return 1;
}
static int kgdb_singlestep(struct pt_regs *regs)
{
if (user_mode(regs))
return 0;
kgdb_handle_exception(0, SIGTRAP, 0, regs);
return 1;
}
static int kgdb_iabr_match(struct pt_regs *regs)
{
if (user_mode(regs))
return 0;
if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
return 0;
return 1;
}
static int kgdb_break_match(struct pt_regs *regs)
{
if (user_mode(regs))
return 0;
if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
return 0;
return 1;
}
#define PACK64(ptr, src) do { *(ptr++) = (src); } while (0)
#define PACK32(ptr, src) do { \
u32 *ptr32; \
ptr32 = (u32 *)ptr; \
*(ptr32++) = (src); \
ptr = (unsigned long *)ptr32; \
} while (0)
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
{
struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
STACK_FRAME_OVERHEAD);
unsigned long *ptr = gdb_regs;
int reg;
memset(gdb_regs, 0, NUMREGBYTES);
/* Regs GPR0-2 */
for (reg = 0; reg < 3; reg++)
PACK64(ptr, regs->gpr[reg]);
/* Regs GPR3-13 are caller saved, not in regs->gpr[] */
ptr += 11;
/* Regs GPR14-31 */
for (reg = 14; reg < 32; reg++)
PACK64(ptr, regs->gpr[reg]);
#ifdef CONFIG_FSL_BOOKE
#ifdef CONFIG_SPE
for (reg = 0; reg < 32; reg++)
PACK64(ptr, p->thread.evr[reg]);
#else
ptr += 32;
#endif
#else
/* fp registers not used by kernel, leave zero */
ptr += 32 * 8 / sizeof(long);
#endif
PACK64(ptr, regs->nip);
PACK64(ptr, regs->msr);
PACK32(ptr, regs->ccr);
PACK64(ptr, regs->link);
PACK64(ptr, regs->ctr);
PACK32(ptr, regs->xer);
BUG_ON((unsigned long)ptr >
(unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
}
#define GDB_SIZEOF_REG sizeof(unsigned long)
#define GDB_SIZEOF_REG_U32 sizeof(u32)
#ifdef CONFIG_FSL_BOOKE
#define GDB_SIZEOF_FLOAT_REG sizeof(unsigned long)
#else
#define GDB_SIZEOF_FLOAT_REG sizeof(u64)
#endif
struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
{
{ "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[0]) },
{ "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[1]) },
{ "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[2]) },
{ "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[3]) },
{ "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[4]) },
{ "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[5]) },
{ "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[6]) },
{ "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[7]) },
{ "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[8]) },
{ "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[9]) },
{ "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[10]) },
{ "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[11]) },
{ "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[12]) },
{ "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[13]) },
{ "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[14]) },
{ "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[15]) },
{ "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[16]) },
{ "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[17]) },
{ "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[18]) },
{ "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[19]) },
{ "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[20]) },
{ "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[21]) },
{ "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[22]) },
{ "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[23]) },
{ "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[24]) },
{ "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[25]) },
{ "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[26]) },
{ "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[27]) },
{ "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[28]) },
{ "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[29]) },
{ "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[30]) },
{ "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[31]) },
{ "f0", GDB_SIZEOF_FLOAT_REG, 0 },
{ "f1", GDB_SIZEOF_FLOAT_REG, 1 },
{ "f2", GDB_SIZEOF_FLOAT_REG, 2 },
{ "f3", GDB_SIZEOF_FLOAT_REG, 3 },
{ "f4", GDB_SIZEOF_FLOAT_REG, 4 },
{ "f5", GDB_SIZEOF_FLOAT_REG, 5 },
{ "f6", GDB_SIZEOF_FLOAT_REG, 6 },
{ "f7", GDB_SIZEOF_FLOAT_REG, 7 },
{ "f8", GDB_SIZEOF_FLOAT_REG, 8 },
{ "f9", GDB_SIZEOF_FLOAT_REG, 9 },
{ "f10", GDB_SIZEOF_FLOAT_REG, 10 },
{ "f11", GDB_SIZEOF_FLOAT_REG, 11 },
{ "f12", GDB_SIZEOF_FLOAT_REG, 12 },
{ "f13", GDB_SIZEOF_FLOAT_REG, 13 },
{ "f14", GDB_SIZEOF_FLOAT_REG, 14 },
{ "f15", GDB_SIZEOF_FLOAT_REG, 15 },
{ "f16", GDB_SIZEOF_FLOAT_REG, 16 },
{ "f17", GDB_SIZEOF_FLOAT_REG, 17 },
{ "f18", GDB_SIZEOF_FLOAT_REG, 18 },
{ "f19", GDB_SIZEOF_FLOAT_REG, 19 },
{ "f20", GDB_SIZEOF_FLOAT_REG, 20 },
{ "f21", GDB_SIZEOF_FLOAT_REG, 21 },
{ "f22", GDB_SIZEOF_FLOAT_REG, 22 },
{ "f23", GDB_SIZEOF_FLOAT_REG, 23 },
{ "f24", GDB_SIZEOF_FLOAT_REG, 24 },
{ "f25", GDB_SIZEOF_FLOAT_REG, 25 },
{ "f26", GDB_SIZEOF_FLOAT_REG, 26 },
{ "f27", GDB_SIZEOF_FLOAT_REG, 27 },
{ "f28", GDB_SIZEOF_FLOAT_REG, 28 },
{ "f29", GDB_SIZEOF_FLOAT_REG, 29 },
{ "f30", GDB_SIZEOF_FLOAT_REG, 30 },
{ "f31", GDB_SIZEOF_FLOAT_REG, 31 },
{ "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, nip) },
{ "msr", GDB_SIZEOF_REG, offsetof(struct pt_regs, msr) },
{ "cr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ccr) },
{ "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, link) },
{ "ctr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ctr) },
{ "xer", GDB_SIZEOF_REG, offsetof(struct pt_regs, xer) },
};
char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
{
if (regno >= DBG_MAX_REG_NUM || regno < 0)
return NULL;
if (regno < 32 || regno >= 64)
/* First 0 -> 31 gpr registers*/
/* pc, msr, ls... registers 64 -> 69 */
memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
dbg_reg_def[regno].size);
if (regno >= 32 && regno < 64) {
/* FP registers 32 -> 63 */
#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
if (current)
memcpy(mem, &current->thread.evr[regno-32],
dbg_reg_def[regno].size);
#else
/* fp registers not used by kernel, leave zero */
memset(mem, 0, dbg_reg_def[regno].size);
#endif
}
return dbg_reg_def[regno].name;
}
int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
{
if (regno >= DBG_MAX_REG_NUM || regno < 0)
return -EINVAL;
if (regno < 32 || regno >= 64)
/* First 0 -> 31 gpr registers*/
/* pc, msr, ls... registers 64 -> 69 */
memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
dbg_reg_def[regno].size);
if (regno >= 32 && regno < 64) {
/* FP registers 32 -> 63 */
#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
memcpy(&current->thread.evr[regno-32], mem,
dbg_reg_def[regno].size);
#else
/* fp registers not used by kernel, leave zero */
return 0;
#endif
}
return 0;
}
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
{
regs->nip = pc;
}
/*
* This function does PowerPC specific procesing for interfacing to gdb.
*/
int kgdb_arch_handle_exception(int vector, int signo, int err_code,
char *remcom_in_buffer, char *remcom_out_buffer,
struct pt_regs *linux_regs)
{
char *ptr = &remcom_in_buffer[1];
unsigned long addr;
switch (remcom_in_buffer[0]) {
/*
* sAA..AA Step one instruction from AA..AA
* This will return an error to gdb ..
*/
case 's':
case 'c':
/* handle the optional parameter */
if (kgdb_hex2long(&ptr, &addr))
linux_regs->nip = addr;
atomic_set(&kgdb_cpu_doing_single_step, -1);
/* set the trace bit if we're stepping */
if (remcom_in_buffer[0] == 's') {
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
mtspr(SPRN_DBCR0,
mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
linux_regs->msr |= MSR_DE;
#else
linux_regs->msr |= MSR_SE;
#endif
atomic_set(&kgdb_cpu_doing_single_step,
raw_smp_processor_id());
}
return 0;
}
return -1;
}
powerpc/kgdb: add kgdb_arch_set/remove_breakpoint() Generic implementation fails to remove breakpoints after init when CONFIG_STRICT_KERNEL_RWX is selected: [ 13.251285] KGDB: BP remove failed: c001c338 [ 13.259587] kgdbts: ERROR PUT: end of test buffer on 'do_fork_test' line 8 expected OK got $E14#aa [ 13.268969] KGDB: re-enter exception: ALL breakpoints killed [ 13.275099] CPU: 0 PID: 1 Comm: init Not tainted 4.18.0-g82bbb913ffd8 #860 [ 13.282836] Call Trace: [ 13.285313] [c60e1ba0] [c0080ef0] kgdb_handle_exception+0x6f4/0x720 (unreliable) [ 13.292618] [c60e1c30] [c000e97c] kgdb_handle_breakpoint+0x3c/0x98 [ 13.298709] [c60e1c40] [c000af54] program_check_exception+0x104/0x700 [ 13.305083] [c60e1c60] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.310845] [c60e1d20] [c02a22ac] run_simple_test+0x2b4/0x2d4 [ 13.316532] [c60e1d30] [c0081698] put_packet+0xb8/0x158 [ 13.321694] [c60e1d60] [c00820b4] gdb_serial_stub+0x230/0xc4c [ 13.327374] [c60e1dc0] [c0080af8] kgdb_handle_exception+0x2fc/0x720 [ 13.333573] [c60e1e50] [c000e928] kgdb_singlestep+0xb4/0xcc [ 13.339068] [c60e1e70] [c000ae1c] single_step_exception+0x90/0xac [ 13.345100] [c60e1e80] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.350865] [c60e1f40] [c000e11c] ret_from_syscall+0x0/0x38 [ 13.356346] Kernel panic - not syncing: Recursive entry to debugger This patch creates powerpc specific version of kgdb_arch_set_breakpoint() and kgdb_arch_remove_breakpoint() using patch_instruction() Fixes: 1e0fc9d1eb2b ("powerpc/Kconfig: Enable STRICT_KERNEL_RWX for some configs") Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2018-09-18 17:26:03 +08:00
int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
{
int err;
unsigned int instr;
unsigned int *addr = (unsigned int *)bpt->bpt_addr;
err = probe_kernel_address(addr, instr);
if (err)
return err;
err = patch_instruction(addr, ppc_inst(BREAK_INSTR));
powerpc/kgdb: add kgdb_arch_set/remove_breakpoint() Generic implementation fails to remove breakpoints after init when CONFIG_STRICT_KERNEL_RWX is selected: [ 13.251285] KGDB: BP remove failed: c001c338 [ 13.259587] kgdbts: ERROR PUT: end of test buffer on 'do_fork_test' line 8 expected OK got $E14#aa [ 13.268969] KGDB: re-enter exception: ALL breakpoints killed [ 13.275099] CPU: 0 PID: 1 Comm: init Not tainted 4.18.0-g82bbb913ffd8 #860 [ 13.282836] Call Trace: [ 13.285313] [c60e1ba0] [c0080ef0] kgdb_handle_exception+0x6f4/0x720 (unreliable) [ 13.292618] [c60e1c30] [c000e97c] kgdb_handle_breakpoint+0x3c/0x98 [ 13.298709] [c60e1c40] [c000af54] program_check_exception+0x104/0x700 [ 13.305083] [c60e1c60] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.310845] [c60e1d20] [c02a22ac] run_simple_test+0x2b4/0x2d4 [ 13.316532] [c60e1d30] [c0081698] put_packet+0xb8/0x158 [ 13.321694] [c60e1d60] [c00820b4] gdb_serial_stub+0x230/0xc4c [ 13.327374] [c60e1dc0] [c0080af8] kgdb_handle_exception+0x2fc/0x720 [ 13.333573] [c60e1e50] [c000e928] kgdb_singlestep+0xb4/0xcc [ 13.339068] [c60e1e70] [c000ae1c] single_step_exception+0x90/0xac [ 13.345100] [c60e1e80] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.350865] [c60e1f40] [c000e11c] ret_from_syscall+0x0/0x38 [ 13.356346] Kernel panic - not syncing: Recursive entry to debugger This patch creates powerpc specific version of kgdb_arch_set_breakpoint() and kgdb_arch_remove_breakpoint() using patch_instruction() Fixes: 1e0fc9d1eb2b ("powerpc/Kconfig: Enable STRICT_KERNEL_RWX for some configs") Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2018-09-18 17:26:03 +08:00
if (err)
return -EFAULT;
*(unsigned int *)bpt->saved_instr = instr;
return 0;
}
int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
{
int err;
unsigned int instr = *(unsigned int *)bpt->saved_instr;
unsigned int *addr = (unsigned int *)bpt->bpt_addr;
err = patch_instruction(addr, ppc_inst(instr));
powerpc/kgdb: add kgdb_arch_set/remove_breakpoint() Generic implementation fails to remove breakpoints after init when CONFIG_STRICT_KERNEL_RWX is selected: [ 13.251285] KGDB: BP remove failed: c001c338 [ 13.259587] kgdbts: ERROR PUT: end of test buffer on 'do_fork_test' line 8 expected OK got $E14#aa [ 13.268969] KGDB: re-enter exception: ALL breakpoints killed [ 13.275099] CPU: 0 PID: 1 Comm: init Not tainted 4.18.0-g82bbb913ffd8 #860 [ 13.282836] Call Trace: [ 13.285313] [c60e1ba0] [c0080ef0] kgdb_handle_exception+0x6f4/0x720 (unreliable) [ 13.292618] [c60e1c30] [c000e97c] kgdb_handle_breakpoint+0x3c/0x98 [ 13.298709] [c60e1c40] [c000af54] program_check_exception+0x104/0x700 [ 13.305083] [c60e1c60] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.310845] [c60e1d20] [c02a22ac] run_simple_test+0x2b4/0x2d4 [ 13.316532] [c60e1d30] [c0081698] put_packet+0xb8/0x158 [ 13.321694] [c60e1d60] [c00820b4] gdb_serial_stub+0x230/0xc4c [ 13.327374] [c60e1dc0] [c0080af8] kgdb_handle_exception+0x2fc/0x720 [ 13.333573] [c60e1e50] [c000e928] kgdb_singlestep+0xb4/0xcc [ 13.339068] [c60e1e70] [c000ae1c] single_step_exception+0x90/0xac [ 13.345100] [c60e1e80] [c000e45c] ret_from_except_full+0x0/0x4 [ 13.350865] [c60e1f40] [c000e11c] ret_from_syscall+0x0/0x38 [ 13.356346] Kernel panic - not syncing: Recursive entry to debugger This patch creates powerpc specific version of kgdb_arch_set_breakpoint() and kgdb_arch_remove_breakpoint() using patch_instruction() Fixes: 1e0fc9d1eb2b ("powerpc/Kconfig: Enable STRICT_KERNEL_RWX for some configs") Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
2018-09-18 17:26:03 +08:00
if (err)
return -EFAULT;
return 0;
}
/*
* Global data
*/
const struct kgdb_arch arch_kgdb_ops;
static int kgdb_not_implemented(struct pt_regs *regs)
{
return 0;
}
static void *old__debugger_ipi;
static void *old__debugger;
static void *old__debugger_bpt;
static void *old__debugger_sstep;
static void *old__debugger_iabr_match;
static void *old__debugger_break_match;
static void *old__debugger_fault_handler;
int kgdb_arch_init(void)
{
old__debugger_ipi = __debugger_ipi;
old__debugger = __debugger;
old__debugger_bpt = __debugger_bpt;
old__debugger_sstep = __debugger_sstep;
old__debugger_iabr_match = __debugger_iabr_match;
old__debugger_break_match = __debugger_break_match;
old__debugger_fault_handler = __debugger_fault_handler;
kgdb: Fix kgdb_roundup_cpus() for arches who used smp_call_function() When I had lockdep turned on and dropped into kgdb I got a nice splat on my system. Specifically it hit: DEBUG_LOCKS_WARN_ON(current->hardirq_context) Specifically it looked like this: sysrq: SysRq : DEBUG ------------[ cut here ]------------ DEBUG_LOCKS_WARN_ON(current->hardirq_context) WARNING: CPU: 0 PID: 0 at .../kernel/locking/lockdep.c:2875 lockdep_hardirqs_on+0xf0/0x160 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.19.0 #27 pstate: 604003c9 (nZCv DAIF +PAN -UAO) pc : lockdep_hardirqs_on+0xf0/0x160 ... Call trace: lockdep_hardirqs_on+0xf0/0x160 trace_hardirqs_on+0x188/0x1ac kgdb_roundup_cpus+0x14/0x3c kgdb_cpu_enter+0x53c/0x5cc kgdb_handle_exception+0x180/0x1d4 kgdb_compiled_brk_fn+0x30/0x3c brk_handler+0x134/0x178 do_debug_exception+0xfc/0x178 el1_dbg+0x18/0x78 kgdb_breakpoint+0x34/0x58 sysrq_handle_dbg+0x54/0x5c __handle_sysrq+0x114/0x21c handle_sysrq+0x30/0x3c qcom_geni_serial_isr+0x2dc/0x30c ... ... irq event stamp: ...45 hardirqs last enabled at (...44): [...] __do_softirq+0xd8/0x4e4 hardirqs last disabled at (...45): [...] el1_irq+0x74/0x130 softirqs last enabled at (...42): [...] _local_bh_enable+0x2c/0x34 softirqs last disabled at (...43): [...] irq_exit+0xa8/0x100 ---[ end trace adf21f830c46e638 ]--- Looking closely at it, it seems like a really bad idea to be calling local_irq_enable() in kgdb_roundup_cpus(). If nothing else that seems like it could violate spinlock semantics and cause a deadlock. Instead, let's use a private csd alongside smp_call_function_single_async() to round up the other CPUs. Using smp_call_function_single_async() doesn't require interrupts to be enabled so we can remove the offending bit of code. In order to avoid duplicating this across all the architectures that use the default kgdb_roundup_cpus(), we'll add a "weak" implementation to debug_core.c. Looking at all the people who previously had copies of this code, there were a few variants. I've attempted to keep the variants working like they used to. Specifically: * For arch/arc we passed NULL to kgdb_nmicallback() instead of get_irq_regs(). * For arch/mips there was a bit of extra code around kgdb_nmicallback() NOTE: In this patch we will still get into trouble if we try to round up a CPU that failed to round up before. We'll try to round it up again and potentially hang when we try to grab the csd lock. That's not new behavior but we'll still try to do better in a future patch. Suggested-by: Daniel Thompson <daniel.thompson@linaro.org> Signed-off-by: Douglas Anderson <dianders@chromium.org> Cc: Vineet Gupta <vgupta@synopsys.com> Cc: Russell King <linux@armlinux.org.uk> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Richard Kuo <rkuo@codeaurora.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Paul Burton <paul.burton@mips.com> Cc: James Hogan <jhogan@kernel.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Cc: Rich Felker <dalias@libc.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: Borislav Petkov <bp@alien8.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
2018-12-05 11:38:26 +08:00
__debugger_ipi = kgdb_debugger_ipi;
__debugger = kgdb_debugger;
__debugger_bpt = kgdb_handle_breakpoint;
__debugger_sstep = kgdb_singlestep;
__debugger_iabr_match = kgdb_iabr_match;
__debugger_break_match = kgdb_break_match;
__debugger_fault_handler = kgdb_not_implemented;
return 0;
}
void kgdb_arch_exit(void)
{
__debugger_ipi = old__debugger_ipi;
__debugger = old__debugger;
__debugger_bpt = old__debugger_bpt;
__debugger_sstep = old__debugger_sstep;
__debugger_iabr_match = old__debugger_iabr_match;
__debugger_break_match = old__debugger_break_match;
__debugger_fault_handler = old__debugger_fault_handler;
}