From 6f7487e127f5cbfc6fbc9b159cae98677b2111e3 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 2 Apr 2014 18:42:13 -0700 Subject: [PATCH] fiq_debugger: split arm support into fiq_debugger_arm.c Split arm support into a separate .c file that is only built for CONFIG_ARM. Change-Id: Iba16f4d51608bf9c3e5c8acefefcd38fead9797c Signed-off-by: Colin Cross --- drivers/staging/android/fiq_debugger/Makefile | 1 + .../android/fiq_debugger/fiq_debugger.c | 223 +--------------- .../android/fiq_debugger/fiq_debugger_arm.c | 240 ++++++++++++++++++ .../android/fiq_debugger/fiq_debugger_priv.h | 36 +++ 4 files changed, 280 insertions(+), 220 deletions(-) create mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_arm.c create mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_priv.h diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile index 437037852963..1e203aed8c62 100644 --- a/drivers/staging/android/fiq_debugger/Makefile +++ b/drivers/staging/android/fiq_debugger/Makefile @@ -1 +1,2 @@ obj-y += fiq_debugger.o +obj-$(CONFIG_ARM) += fiq_debugger_arm.o diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c index d660a46e7893..5516d3113b94 100644 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.c +++ b/drivers/staging/android/fiq_debugger/fiq_debugger.c @@ -38,11 +38,11 @@ #ifdef CONFIG_FIQ_GLUE #include #endif -#include #include #include "fiq_debugger.h" +#include "fiq_debugger_priv.h" #include "fiq_debugger_ringbuf.h" #define DEBUG_MAX 64 @@ -50,9 +50,6 @@ #define MAX_FIQ_DEBUGGER_PORTS 4 -#define THREAD_INFO(sp) ((struct thread_info *) \ - ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) - struct fiq_debugger_state { #ifdef CONFIG_FIQ_GLUE struct fiq_glue_handler handler; @@ -232,21 +229,7 @@ static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state) } } -static char *mode_name(unsigned cpsr) -{ - switch (cpsr & MODE_MASK) { - case USR_MODE: return "USR"; - case FIQ_MODE: return "FIQ"; - case IRQ_MODE: return "IRQ"; - case SVC_MODE: return "SVC"; - case ABT_MODE: return "ABT"; - case UND_MODE: return "UND"; - case SYSTEM_MODE: return "SYS"; - default: return "???"; - } -} - -static int fiq_debugger_printf(void *cookie, const char *fmt, ...) +int fiq_debugger_printf(void *cookie, const char *fmt, ...) { struct fiq_debugger_state *state = cookie; char buf[256]; @@ -279,112 +262,6 @@ static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...) return state->debug_abort; } -static void fiq_debugger_dump_regs(struct fiq_debugger_state *state, - const struct pt_regs *regs) -{ - fiq_debugger_printf(state, - " r0 %08x r1 %08x r2 %08x r3 %08x\n", - regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); - fiq_debugger_printf(state, - " r4 %08x r5 %08x r6 %08x r7 %08x\n", - regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7); - fiq_debugger_printf(state, - " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", - regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp, - mode_name(regs->ARM_cpsr)); - fiq_debugger_printf(state, - " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", - regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc, - regs->ARM_cpsr); -} - -struct mode_regs { - unsigned long sp_svc; - unsigned long lr_svc; - unsigned long spsr_svc; - - unsigned long sp_abt; - unsigned long lr_abt; - unsigned long spsr_abt; - - unsigned long sp_und; - unsigned long lr_und; - unsigned long spsr_und; - - unsigned long sp_irq; - unsigned long lr_irq; - unsigned long spsr_irq; - - unsigned long r8_fiq; - unsigned long r9_fiq; - unsigned long r10_fiq; - unsigned long r11_fiq; - unsigned long r12_fiq; - unsigned long sp_fiq; - unsigned long lr_fiq; - unsigned long spsr_fiq; -}; - -void __naked get_mode_regs(struct mode_regs *regs) -{ - asm volatile ( - "mrs r1, cpsr\n" - "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r8 - r14}\n" - "mrs r2, spsr\n" - "stmia r0!, {r2}\n" - "msr cpsr_c, r1\n" - "bx lr\n"); -} - - -static void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, - const struct pt_regs *regs) -{ - struct mode_regs mode_regs; - unsigned long mode = regs->ARM_cpsr & MODE_MASK; - - fiq_debugger_dump_regs(state, regs); - get_mode_regs(&mode_regs); - - fiq_debugger_printf(state, - "%csvc: sp %08x lr %08x spsr %08x\n", - mode == SVC_MODE ? '*' : ' ', - mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); - fiq_debugger_printf(state, - "%cabt: sp %08x lr %08x spsr %08x\n", - mode == ABT_MODE ? '*' : ' ', - mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); - fiq_debugger_printf(state, - "%cund: sp %08x lr %08x spsr %08x\n", - mode == UND_MODE ? '*' : ' ', - mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); - fiq_debugger_printf(state, - "%cirq: sp %08x lr %08x spsr %08x\n", - mode == IRQ_MODE ? '*' : ' ', - mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); - fiq_debugger_printf(state, - "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", - mode == FIQ_MODE ? '*' : ' ', - mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, - mode_regs.r11_fiq, mode_regs.r12_fiq); - fiq_debugger_printf(state, - " fiq: sp %08x lr %08x spsr %08x\n", - mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); -} - static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state) { int n; @@ -405,98 +282,6 @@ static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state) } } -struct stacktrace_state { - struct fiq_debugger_state *state; - unsigned int depth; -}; - -static int report_trace(struct stackframe *frame, void *d) -{ - struct stacktrace_state *sts = d; - - if (sts->depth) { - fiq_debugger_printf(sts->state, - " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", - frame->pc, frame->pc, frame->lr, frame->lr, - frame->sp, frame->fp); - sts->depth--; - return 0; - } - fiq_debugger_printf(sts->state, " ...\n"); - - return sts->depth == 0; -} - -struct frame_tail { - struct frame_tail *fp; - unsigned long sp; - unsigned long lr; -} __attribute__((packed)); - -static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, - struct frame_tail *tail) -{ - struct frame_tail buftail[2]; - - /* Also check accessibility of one struct frame_tail beyond */ - if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { - fiq_debugger_printf(state, " invalid frame pointer %p\n", - tail); - return NULL; - } - if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { - fiq_debugger_printf(state, - " failed to copy frame pointer %p\n", tail); - return NULL; - } - - fiq_debugger_printf(state, " %p\n", buftail[0].lr); - - /* frame pointers should strictly progress back up the stack - * (towards higher addresses) */ - if (tail >= buftail[0].fp) - return NULL; - - return buftail[0].fp-1; -} - -void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, - const struct pt_regs *regs, unsigned int depth, void *ssp) -{ - struct frame_tail *tail; - struct thread_info *real_thread_info = THREAD_INFO(ssp); - struct stacktrace_state sts; - - sts.depth = depth; - sts.state = state; - *current_thread_info() = *real_thread_info; - - if (!current) - fiq_debugger_printf(state, "current NULL\n"); - else - fiq_debugger_printf(state, "pid: %d comm: %s\n", - current->pid, current->comm); - fiq_debugger_dump_regs(state, regs); - - if (!user_mode(regs)) { - struct stackframe frame; - frame.fp = regs->ARM_fp; - frame.sp = regs->ARM_sp; - frame.lr = regs->ARM_lr; - frame.pc = regs->ARM_pc; - fiq_debugger_printf(state, - " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", - regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, - regs->ARM_sp, regs->ARM_fp); - walk_stackframe(&frame, report_trace, &sts); - return; - } - - tail = ((struct frame_tail *) regs->ARM_fp) - 1; - while (depth-- && tail && !((unsigned long) tail & 3)) - tail = user_backtrace(state, tail); -} - static void fiq_debugger_do_ps(struct fiq_debugger_state *state) { struct task_struct *g; @@ -692,9 +477,7 @@ static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { fiq_debugger_help(state); } else if (!strcmp(cmd, "pc")) { - fiq_debugger_printf(state, " pc %08x cpsr %08x mode %s\n", - regs->ARM_pc, regs->ARM_cpsr, - mode_name(regs->ARM_cpsr)); + fiq_debugger_dump_pc(state, regs); } else if (!strcmp(cmd, "regs")) { fiq_debugger_dump_regs(state, regs); } else if (!strcmp(cmd, "allregs")) { diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c new file mode 100644 index 000000000000..fca12737d224 --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Colin Cross + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include + +#include "fiq_debugger_priv.h" + +static char *mode_name(unsigned cpsr) +{ + switch (cpsr & MODE_MASK) { + case USR_MODE: return "USR"; + case FIQ_MODE: return "FIQ"; + case IRQ_MODE: return "IRQ"; + case SVC_MODE: return "SVC"; + case ABT_MODE: return "ABT"; + case UND_MODE: return "UND"; + case SYSTEM_MODE: return "SYS"; + default: return "???"; + } +} + +void fiq_debugger_dump_pc(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + fiq_debugger_printf(state, " pc %08x cpsr %08x mode %s\n", + regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr)); +} + +void fiq_debugger_dump_regs(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + fiq_debugger_printf(state, + " r0 %08x r1 %08x r2 %08x r3 %08x\n", + regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); + fiq_debugger_printf(state, + " r4 %08x r5 %08x r6 %08x r7 %08x\n", + regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7); + fiq_debugger_printf(state, + " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", + regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp, + mode_name(regs->ARM_cpsr)); + fiq_debugger_printf(state, + " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", + regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc, + regs->ARM_cpsr); +} + +struct mode_regs { + unsigned long sp_svc; + unsigned long lr_svc; + unsigned long spsr_svc; + + unsigned long sp_abt; + unsigned long lr_abt; + unsigned long spsr_abt; + + unsigned long sp_und; + unsigned long lr_und; + unsigned long spsr_und; + + unsigned long sp_irq; + unsigned long lr_irq; + unsigned long spsr_irq; + + unsigned long r8_fiq; + unsigned long r9_fiq; + unsigned long r10_fiq; + unsigned long r11_fiq; + unsigned long r12_fiq; + unsigned long sp_fiq; + unsigned long lr_fiq; + unsigned long spsr_fiq; +}; + +static void __naked get_mode_regs(struct mode_regs *regs) +{ + asm volatile ( + "mrs r1, cpsr\n" + "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r8 - r14}\n" + "mrs r2, spsr\n" + "stmia r0!, {r2}\n" + "msr cpsr_c, r1\n" + "bx lr\n"); +} + + +void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, + const struct pt_regs *regs) +{ + struct mode_regs mode_regs; + unsigned long mode = regs->ARM_cpsr & MODE_MASK; + + fiq_debugger_dump_regs(state, regs); + get_mode_regs(&mode_regs); + + fiq_debugger_printf(state, + "%csvc: sp %08x lr %08x spsr %08x\n", + mode == SVC_MODE ? '*' : ' ', + mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); + fiq_debugger_printf(state, + "%cabt: sp %08x lr %08x spsr %08x\n", + mode == ABT_MODE ? '*' : ' ', + mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); + fiq_debugger_printf(state, + "%cund: sp %08x lr %08x spsr %08x\n", + mode == UND_MODE ? '*' : ' ', + mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); + fiq_debugger_printf(state, + "%cirq: sp %08x lr %08x spsr %08x\n", + mode == IRQ_MODE ? '*' : ' ', + mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); + fiq_debugger_printf(state, + "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", + mode == FIQ_MODE ? '*' : ' ', + mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, + mode_regs.r11_fiq, mode_regs.r12_fiq); + fiq_debugger_printf(state, + " fiq: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); +} + +struct stacktrace_state { + struct fiq_debugger_state *state; + unsigned int depth; +}; + +static int report_trace(struct stackframe *frame, void *d) +{ + struct stacktrace_state *sts = d; + + if (sts->depth) { + fiq_debugger_printf(sts->state, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + frame->pc, frame->pc, frame->lr, frame->lr, + frame->sp, frame->fp); + sts->depth--; + return 0; + } + fiq_debugger_printf(sts->state, " ...\n"); + + return sts->depth == 0; +} + +struct frame_tail { + struct frame_tail *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + +static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, + struct frame_tail *tail) +{ + struct frame_tail buftail[2]; + + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { + fiq_debugger_printf(state, " invalid frame pointer %p\n", + tail); + return NULL; + } + if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { + fiq_debugger_printf(state, + " failed to copy frame pointer %p\n", tail); + return NULL; + } + + fiq_debugger_printf(state, " %p\n", buftail[0].lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= buftail[0].fp) + return NULL; + + return buftail[0].fp-1; +} + +void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, + const struct pt_regs *regs, unsigned int depth, void *ssp) +{ + struct frame_tail *tail; + struct thread_info *real_thread_info = THREAD_INFO(ssp); + struct stacktrace_state sts; + + sts.depth = depth; + sts.state = state; + *current_thread_info() = *real_thread_info; + + if (!current) + fiq_debugger_printf(state, "current NULL\n"); + else + fiq_debugger_printf(state, "pid: %d comm: %s\n", + current->pid, current->comm); + fiq_debugger_dump_regs(state, regs); + + if (!user_mode(regs)) { + struct stackframe frame; + frame.fp = regs->ARM_fp; + frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; + frame.pc = regs->ARM_pc; + fiq_debugger_printf(state, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, + regs->ARM_sp, regs->ARM_fp); + walk_stackframe(&frame, report_trace, &sts); + return; + } + + tail = ((struct frame_tail *) regs->ARM_fp) - 1; + while (depth-- && tail && !((unsigned long) tail & 3)) + tail = user_backtrace(state, tail); +} diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h new file mode 100644 index 000000000000..746cf1b5d55b --- /dev/null +++ b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Google, Inc. + * Author: Colin Cross + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _FIQ_DEBUGGER_PRIV_H_ +#define _FIQ_DEBUGGER_PRIV_H_ + +#define THREAD_INFO(sp) ((struct thread_info *) \ + ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) + +struct fiq_debugger_state; +struct pt_regs; + +int fiq_debugger_printf(void *cookie, const char *fmt, ...); + +void fiq_debugger_dump_pc(struct fiq_debugger_state *state, + const struct pt_regs *regs); +void fiq_debugger_dump_regs(struct fiq_debugger_state *state, + const struct pt_regs *regs); +void fiq_debugger_dump_allregs(struct fiq_debugger_state *state, + const struct pt_regs *regs); +void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state, + const struct pt_regs *regs, unsigned int depth, void *ssp); + +#endif -- 2.34.1