Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efffceb1 authored by Colin Cross's avatar Colin Cross Committed by Amit Pundir
Browse files

ANDROID: 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: default avatarColin Cross <ccross@android.com>
parent bf32f8ac
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
obj-y			+= fiq_debugger.o
obj-y			+= fiq_debugger.o
obj-$(CONFIG_ARM)	+= fiq_debugger_arm.o
+3 −220
Original line number Original line Diff line number Diff line
@@ -38,11 +38,11 @@
#ifdef CONFIG_FIQ_GLUE
#ifdef CONFIG_FIQ_GLUE
#include <asm/fiq_glue.h>
#include <asm/fiq_glue.h>
#endif
#endif
#include <asm/stacktrace.h>


#include <linux/uaccess.h>
#include <linux/uaccess.h>


#include "fiq_debugger.h"
#include "fiq_debugger.h"
#include "fiq_debugger_priv.h"
#include "fiq_debugger_ringbuf.h"
#include "fiq_debugger_ringbuf.h"


#define DEBUG_MAX 64
#define DEBUG_MAX 64
@@ -50,9 +50,6 @@


#define MAX_FIQ_DEBUGGER_PORTS 4
#define MAX_FIQ_DEBUGGER_PORTS 4


#define THREAD_INFO(sp) ((struct thread_info *) \
		((unsigned long)(sp) & ~(THREAD_SIZE - 1)))

struct fiq_debugger_state {
struct fiq_debugger_state {
#ifdef CONFIG_FIQ_GLUE
#ifdef CONFIG_FIQ_GLUE
	struct fiq_glue_handler handler;
	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)
int fiq_debugger_printf(void *cookie, const char *fmt, ...)
{
	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, ...)
{
{
	struct fiq_debugger_state *state = cookie;
	struct fiq_debugger_state *state = cookie;
	char buf[256];
	char buf[256];
@@ -279,112 +262,6 @@ static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...)
	return state->debug_abort;
	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)
static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state)
{
{
	int n;
	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)
static void fiq_debugger_do_ps(struct fiq_debugger_state *state)
{
{
	struct task_struct *g;
	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, "?")) {
	if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) {
		fiq_debugger_help(state);
		fiq_debugger_help(state);
	} else if (!strcmp(cmd, "pc")) {
	} else if (!strcmp(cmd, "pc")) {
		fiq_debugger_printf(state, " pc %08x cpsr %08x mode %s\n",
		fiq_debugger_dump_pc(state, regs);
			regs->ARM_pc, regs->ARM_cpsr,
			mode_name(regs->ARM_cpsr));
	} else if (!strcmp(cmd, "regs")) {
	} else if (!strcmp(cmd, "regs")) {
		fiq_debugger_dump_regs(state, regs);
		fiq_debugger_dump_regs(state, regs);
	} else if (!strcmp(cmd, "allregs")) {
	} else if (!strcmp(cmd, "allregs")) {
+240 −0
Original line number Original line Diff line number Diff line
/*
 * 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 <linux/uaccess.h>

#include <asm/stacktrace.h>

#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);
}
+36 −0
Original line number Original line Diff line number Diff line
/*
 * 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.
 *
 */

#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