// SPDX-License-Identifier: GPL-2.0 /* * SuperH KGDB support * * Copyright (C) 2008 - 2012 Paul Mundt * * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel.
*/ #include <linux/kgdb.h> #include <linux/kdebug.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/sched.h> #include <linux/sched/task_stack.h>
/* Calculate the new address for after a step */ staticshort *get_step_address(struct pt_regs *linux_regs)
{
insn_size_t op = __raw_readw(linux_regs->pc); long addr;
/* * Replace the instruction immediately after the current instruction * (i.e. next in the expected flow of control) with a trap instruction, * so that returning will cause only a single instruction to be executed. * Note that this model is slightly broken for instructions with delay * slots (e.g. B[TF]S, BSR, BRA etc), where both the branch and the * instruction in the delay slot will be executed.
*/
staticvoid do_single_step(struct pt_regs *linux_regs)
{ /* Determine where the target instruction will send us to */ unsignedshort *addr = get_step_address(linux_regs);
stepped_address = (int)addr;
/* Replace it */
stepped_opcode = __raw_readw((long)addr);
*addr = STEP_OPCODE;
/* Flush and return */
flush_icache_range((long)addr, (long)addr +
instruction_size(stepped_opcode));
}
/* Undo a single step */ staticvoid undo_single_step(struct pt_regs *linux_regs)
{ /* If we have stepped, put back the old instruction */ /* Use stepped_address in case we stopped elsewhere */ if (stepped_opcode != 0) {
__raw_writew(stepped_opcode, stepped_address);
flush_icache_range(stepped_address, stepped_address + 2);
}
/* Initialize to zero */ for (reg = 0; reg < DBG_MAX_REG_NUM; reg++)
gdb_regs[reg] = 0;
/* * Copy out GP regs 8 to 14. * * switch_to() relies on SR.RB toggling, so regs 0->7 are banked * and need privileged instructions to get to. The r15 value we * fetch from the thread info directly.
*/ for (reg = GDB_R8; reg < GDB_R15; reg++)
gdb_regs[reg] = thread_regs->regs[reg];
staticint __kgdb_notify(struct die_args *args, unsignedlong cmd)
{ int ret;
switch (cmd) { case DIE_BREAKPOINT: /* * This means a user thread is single stepping * a system call which should be ignored
*/ if (test_thread_flag(TIF_SINGLESTEP)) return NOTIFY_DONE;
ret = kgdb_handle_exception(args->trapnr & 0xff, args->signr,
args->err, args->regs); if (ret) return NOTIFY_DONE;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.