aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2017-03-30 11:06:02 -0400
committerRalf Baechle <ralf@linux-mips.org>2017-04-12 16:29:22 -0400
commit162b270c664dca2e0944308e92f9fcc887151a72 (patch)
tree5688244972f039ca87ac2621fa242e0b3aaa3b4a
parentbac06cf0fb9dfd79877a4eaa2ec7c09a6b853ffa (diff)
MIPS: KGDB: Use kernel context for sleeping threads
KGDB is a kernel debug stub and it can't be used to debug userland as it can only safely access kernel memory. On MIPS however KGDB has always got the register state of sleeping processes from the userland register context at the beginning of the kernel stack. This is meaningless for kernel threads (which never enter userland), and for user threads it prevents the user seeing what it is doing while in the kernel: (gdb) info threads Id Target Id Frame ... 3 Thread 2 (kthreadd) 0x0000000000000000 in ?? () 2 Thread 1 (init) 0x000000007705c4b4 in ?? () 1 Thread -2 (shadowCPU0) 0xffffffff8012524c in arch_kgdb_breakpoint () at arch/mips/kernel/kgdb.c:201 Get the register state instead from the (partial) kernel register context stored in the task's thread_struct for resume() to restore. All threads now correctly appear to be in context_switch(): (gdb) info threads Id Target Id Frame ... 3 Thread 2 (kthreadd) context_switch (rq=<optimized out>, cookie=..., next=<optimized out>, prev=0x0) at kernel/sched/core.c:2903 2 Thread 1 (init) context_switch (rq=<optimized out>, cookie=..., next=<optimized out>, prev=0x0) at kernel/sched/core.c:2903 1 Thread -2 (shadowCPU0) 0xffffffff8012524c in arch_kgdb_breakpoint () at arch/mips/kernel/kgdb.c:201 Call clobbered registers which aren't saved and exception registers (BadVAddr & Cause) which can't be easily determined without stack unwinding are reported as 0. The PC is taken from the return address, such that the state presented matches that found immediately after returning from resume(). Fixes: 8854700115ec ("[MIPS] kgdb: add arch support for the kernel's kgdb core") Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Jason Wessel <jason.wessel@windriver.com> Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/15829/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/kernel/kgdb.c48
1 files changed, 33 insertions, 15 deletions
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
index 1f4bd222ba76..eb6c0d582626 100644
--- a/arch/mips/kernel/kgdb.c
+++ b/arch/mips/kernel/kgdb.c
@@ -244,9 +244,6 @@ static int compute_signal(int tt)
244void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) 244void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
245{ 245{
246 int reg; 246 int reg;
247 struct thread_info *ti = task_thread_info(p);
248 unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32;
249 struct pt_regs *regs = (struct pt_regs *)ksp - 1;
250#if (KGDB_GDB_REG_SIZE == 32) 247#if (KGDB_GDB_REG_SIZE == 32)
251 u32 *ptr = (u32 *)gdb_regs; 248 u32 *ptr = (u32 *)gdb_regs;
252#else 249#else
@@ -254,25 +251,46 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
254#endif 251#endif
255 252
256 for (reg = 0; reg < 16; reg++) 253 for (reg = 0; reg < 16; reg++)
257 *(ptr++) = regs->regs[reg]; 254 *(ptr++) = 0;
258 255
259 /* S0 - S7 */ 256 /* S0 - S7 */
260 for (reg = 16; reg < 24; reg++) 257 *(ptr++) = p->thread.reg16;
261 *(ptr++) = regs->regs[reg]; 258 *(ptr++) = p->thread.reg17;
259 *(ptr++) = p->thread.reg18;
260 *(ptr++) = p->thread.reg19;
261 *(ptr++) = p->thread.reg20;
262 *(ptr++) = p->thread.reg21;
263 *(ptr++) = p->thread.reg22;
264 *(ptr++) = p->thread.reg23;
262 265
263 for (reg = 24; reg < 28; reg++) 266 for (reg = 24; reg < 28; reg++)
264 *(ptr++) = 0; 267 *(ptr++) = 0;
265 268
266 /* GP, SP, FP, RA */ 269 /* GP, SP, FP, RA */
267 for (reg = 28; reg < 32; reg++) 270 *(ptr++) = (long)p;
268 *(ptr++) = regs->regs[reg]; 271 *(ptr++) = p->thread.reg29;
269 272 *(ptr++) = p->thread.reg30;
270 *(ptr++) = regs->cp0_status; 273 *(ptr++) = p->thread.reg31;
271 *(ptr++) = regs->lo; 274
272 *(ptr++) = regs->hi; 275 *(ptr++) = p->thread.cp0_status;
273 *(ptr++) = regs->cp0_badvaddr; 276
274 *(ptr++) = regs->cp0_cause; 277 /* lo, hi */
275 *(ptr++) = regs->cp0_epc; 278 *(ptr++) = 0;
279 *(ptr++) = 0;
280
281 /*
282 * BadVAddr, Cause
283 * Ideally these would come from the last exception frame up the stack
284 * but that requires unwinding, otherwise we can't know much for sure.
285 */
286 *(ptr++) = 0;
287 *(ptr++) = 0;
288
289 /*
290 * PC
291 * use return address (RA), i.e. the moment after return from resume()
292 */
293 *(ptr++) = p->thread.reg31;
276} 294}
277 295
278void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) 296void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)