ANDROID: fiq_debugger: add ARM64 support
authorColin Cross <ccross@android.com>
Thu, 3 Apr 2014 01:49:39 +0000 (18:49 -0700)
committerAmit Pundir <amit.pundir@linaro.org>
Mon, 18 Dec 2017 15:41:22 +0000 (21:11 +0530)
Add fiq_debugger_arm64.c that implements the platform-specific
functions.

Change-Id: I4d8b96777bb8503a93d4eb47bbde8e018740a5bf
Signed-off-by: Colin Cross <ccross@android.com>
[AmitP: Remove unused stackframe -> sp to align with upstream commit
        31e43ad3b74a ("arm64: unwind: remove sp from struct stackframe")

        Also folded following android-4.9 commit changes into this patch
        a33d9f9fa333 ("ANDROID: fiq_debugger: Pass task parameter to unwind_frame()")]
Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
drivers/staging/android/fiq_debugger/Kconfig
drivers/staging/android/fiq_debugger/Makefile
drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c [new file with mode: 0644]

index 803fb59cc82f207ec93c43102bf3d2bafd55b3b3..d87978cc7deecce17ee691fe2015b806adc32b83 100644 (file)
@@ -1,7 +1,7 @@
 config FIQ_DEBUGGER
        bool "FIQ Mode Serial Debugger"
        default n
-       depends on ARM
+       depends on ARM || ARM64
        help
          The FIQ serial debugger can accept commands even when the
          kernel is unresponsive due to being stuck with interrupts
index 1e203aed8c62a389f57961320a388c5f65cb945a..c95da7eb1b33c216574561000162101e2e898b67 100644 (file)
@@ -1,2 +1,3 @@
 obj-y                  += fiq_debugger.o
 obj-$(CONFIG_ARM)      += fiq_debugger_arm.o
+obj-$(CONFIG_ARM64)    += fiq_debugger_arm64.o
\ No newline at end of file
diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c
new file mode 100644 (file)
index 0000000..92a8eca
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * 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 <linux/ptrace.h>
+#include <asm/stacktrace.h>
+
+#include "fiq_debugger_priv.h"
+
+static char *mode_name(const struct pt_regs *regs)
+{
+       if (compat_user_mode(regs)) {
+               return "USR";
+       } else {
+               switch (processor_mode(regs)) {
+               case PSR_MODE_EL0t: return "EL0t";
+               case PSR_MODE_EL1t: return "EL1t";
+               case PSR_MODE_EL1h: return "EL1h";
+               case PSR_MODE_EL2t: return "EL2t";
+               case PSR_MODE_EL2h: return "EL2h";
+               default: return "???";
+               }
+       }
+}
+
+void fiq_debugger_dump_pc(struct fiq_debugger_state *state,
+               const struct pt_regs *regs)
+{
+       fiq_debugger_printf(state, " pc %016lx cpsr %08lx mode %s\n",
+               regs->pc, regs->pstate, mode_name(regs));
+}
+
+void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_state *state,
+               const struct pt_regs *regs)
+{
+       fiq_debugger_printf(state, " r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
+                       regs->compat_usr(0), regs->compat_usr(1),
+                       regs->compat_usr(2), regs->compat_usr(3));
+       fiq_debugger_printf(state, " r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
+                       regs->compat_usr(4), regs->compat_usr(5),
+                       regs->compat_usr(6), regs->compat_usr(7));
+       fiq_debugger_printf(state, " r8 %08x  r9 %08x r10 %08x r11 %08x\n",
+                       regs->compat_usr(8), regs->compat_usr(9),
+                       regs->compat_usr(10), regs->compat_usr(11));
+       fiq_debugger_printf(state, " ip %08x  sp %08x  lr %08x  pc %08x\n",
+                       regs->compat_usr(12), regs->compat_sp,
+                       regs->compat_lr, regs->pc);
+       fiq_debugger_printf(state, " cpsr %08x (%s)\n",
+                       regs->pstate, mode_name(regs));
+}
+
+void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_state *state,
+               const struct pt_regs *regs)
+{
+
+       fiq_debugger_printf(state, "  x0 %016lx   x1 %016lx\n",
+                       regs->regs[0], regs->regs[1]);
+       fiq_debugger_printf(state, "  x2 %016lx   x3 %016lx\n",
+                       regs->regs[2], regs->regs[3]);
+       fiq_debugger_printf(state, "  x4 %016lx   x5 %016lx\n",
+                       regs->regs[4], regs->regs[5]);
+       fiq_debugger_printf(state, "  x6 %016lx   x7 %016lx\n",
+                       regs->regs[6], regs->regs[7]);
+       fiq_debugger_printf(state, "  x8 %016lx   x9 %016lx\n",
+                       regs->regs[8], regs->regs[9]);
+       fiq_debugger_printf(state, " x10 %016lx  x11 %016lx\n",
+                       regs->regs[10], regs->regs[11]);
+       fiq_debugger_printf(state, " x12 %016lx  x13 %016lx\n",
+                       regs->regs[12], regs->regs[13]);
+       fiq_debugger_printf(state, " x14 %016lx  x15 %016lx\n",
+                       regs->regs[14], regs->regs[15]);
+       fiq_debugger_printf(state, " x16 %016lx  x17 %016lx\n",
+                       regs->regs[16], regs->regs[17]);
+       fiq_debugger_printf(state, " x18 %016lx  x19 %016lx\n",
+                       regs->regs[18], regs->regs[19]);
+       fiq_debugger_printf(state, " x20 %016lx  x21 %016lx\n",
+                       regs->regs[20], regs->regs[21]);
+       fiq_debugger_printf(state, " x22 %016lx  x23 %016lx\n",
+                       regs->regs[22], regs->regs[23]);
+       fiq_debugger_printf(state, " x24 %016lx  x25 %016lx\n",
+                       regs->regs[24], regs->regs[25]);
+       fiq_debugger_printf(state, " x26 %016lx  x27 %016lx\n",
+                       regs->regs[26], regs->regs[27]);
+       fiq_debugger_printf(state, " x28 %016lx  x29 %016lx\n",
+                       regs->regs[28], regs->regs[29]);
+       fiq_debugger_printf(state, " x30 %016lx   sp %016lx\n",
+                       regs->regs[30], regs->sp);
+       fiq_debugger_printf(state, "  pc %016lx cpsr %08x (%s)\n",
+                       regs->pc, regs->pstate, mode_name(regs));
+}
+
+void fiq_debugger_dump_regs(struct fiq_debugger_state *state,
+               const struct pt_regs *regs)
+{
+       if (compat_user_mode(regs))
+               fiq_debugger_dump_regs_aarch32(state, regs);
+       else
+               fiq_debugger_dump_regs_aarch64(state, regs);
+}
+
+#define READ_SPECIAL_REG(x) ({ \
+       u64 val; \
+       asm volatile ("mrs %0, " # x : "=r"(val)); \
+       val; \
+})
+
+void fiq_debugger_dump_allregs(struct fiq_debugger_state *state,
+               const struct pt_regs *regs)
+{
+       u32 pstate = READ_SPECIAL_REG(CurrentEl);
+       bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t;
+
+       fiq_debugger_dump_regs(state, regs);
+
+       fiq_debugger_printf(state, " sp_el0   %016lx\n",
+                       READ_SPECIAL_REG(sp_el0));
+
+       if (in_el2)
+               fiq_debugger_printf(state, " sp_el1   %016lx\n",
+                               READ_SPECIAL_REG(sp_el1));
+
+       fiq_debugger_printf(state, " elr_el1  %016lx\n",
+                       READ_SPECIAL_REG(elr_el1));
+
+       fiq_debugger_printf(state, " spsr_el1 %08lx\n",
+                       READ_SPECIAL_REG(spsr_el1));
+
+       if (in_el2) {
+               fiq_debugger_printf(state, " spsr_irq %08lx\n",
+                               READ_SPECIAL_REG(spsr_irq));
+               fiq_debugger_printf(state, " spsr_abt %08lx\n",
+                               READ_SPECIAL_REG(spsr_abt));
+               fiq_debugger_printf(state, " spsr_und %08lx\n",
+                               READ_SPECIAL_REG(spsr_und));
+               fiq_debugger_printf(state, " spsr_fiq %08lx\n",
+                               READ_SPECIAL_REG(spsr_fiq));
+               fiq_debugger_printf(state, " spsr_el2 %08lx\n",
+                               READ_SPECIAL_REG(elr_el2));
+               fiq_debugger_printf(state, " spsr_el2 %08lx\n",
+                               READ_SPECIAL_REG(spsr_el2));
+       }
+}
+
+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, "%pF:\n", frame->pc);
+               fiq_debugger_printf(sts->state,
+                               "  pc %016lx   fp %016lx\n",
+                               frame->pc, frame->fp);
+               sts->depth--;
+               return 0;
+       }
+       fiq_debugger_printf(sts->state, "  ...\n");
+
+       return sts->depth == 0;
+}
+
+void fiq_debugger_dump_stacktrace(struct fiq_debugger_state *state,
+               const struct pt_regs *regs, unsigned int depth, void *ssp)
+{
+       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->regs[29];
+               frame.pc = regs->pc;
+               fiq_debugger_printf(state, "\n");
+               walk_stackframe(current, &frame, report_trace, &sts);
+       }
+}