The save_ptregs() function has been verified to work. Signed-off-by: David VomLehn <dvomlehn@xxxxxxxxx> --- arch/mips/include/asm/ptrace.h | 134 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 134 insertions(+), 0 deletions(-) diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index ce47118..2b75856 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -114,10 +114,13 @@ struct pt_watch_regs { #ifdef __KERNEL__ +#include <linux/kernel.h> #include <linux/compiler.h> #include <linux/linkage.h> #include <linux/types.h> #include <asm/isadep.h> +#include <asm/mipsregs.h> +#include <asm/asm.h> struct task_struct; @@ -139,6 +142,7 @@ extern int ptrace_set_watch_regs(struct task_struct *child, #define instruction_pointer(regs) ((regs)->cp0_epc) #define profile_pc(regs) instruction_pointer(regs) +extern void show_regs(struct pt_regs *regs); extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit); @@ -150,6 +154,136 @@ static inline void die_if_kernel(const char *str, const struct pt_regs *regs) die(str, regs); } +#include <linux/ptreg.h> + +#define PTREG_SAVE(r, name) STR(LONG_S) " " #r ", %[" #name "]\n" +#define PTREG_SAVE_GPR(i) _PTREG_SAVE_IDX($, gpr, i) + +#define PTREG_OUT_GPR(regsp, i) _PTREG_OUT_IDX(regsp, regs, gpr, i) + +#define arch_has_save_ptregs 1 + +/** + * save_ptregs - save processor registers for backtracing + * @regs: Pointer to &struct pt_regs structure in which to save the + * registers + * + * Returns a constant pointer to @regs. + * + * This saves all the GPRs and the EPC, Cause, and Status values for + * coprocessor 0. + * + * This function must be called first in a function. There must be no + * auto variables defined that are initialized before calling this function. + */ +static __always_inline +const struct pt_regs *save_ptregs(register struct pt_regs *regs) +{ + /* The compiler restricts us to 30 operands in an asm construct, so we + * have to break the register saving into two pieces. We can skip + * saving the zero register in the first piece, since its value is + * constant. Since we can ensure no calls are made between the two + * pieces, we can also delay saving the ra register to the second + * piece. */ + __asm__ __volatile__ ( + " .set noat\n" + PTREG_SAVE_GPR(1) + " .set at\n" + PTREG_SAVE_GPR(2) + PTREG_SAVE_GPR(3) + PTREG_SAVE_GPR(4) + PTREG_SAVE_GPR(5) + PTREG_SAVE_GPR(6) + PTREG_SAVE_GPR(7) + PTREG_SAVE_GPR(8) + PTREG_SAVE_GPR(9) + PTREG_SAVE_GPR(10) + PTREG_SAVE_GPR(11) + PTREG_SAVE_GPR(12) + PTREG_SAVE_GPR(13) + PTREG_SAVE_GPR(14) + PTREG_SAVE_GPR(15) + PTREG_SAVE_GPR(16) + PTREG_SAVE_GPR(17) + PTREG_SAVE_GPR(18) + PTREG_SAVE_GPR(19) + PTREG_SAVE_GPR(20) + PTREG_SAVE_GPR(21) + PTREG_SAVE_GPR(22) + PTREG_SAVE_GPR(23) + PTREG_SAVE_GPR(24) + PTREG_SAVE_GPR(25) + PTREG_SAVE_GPR(26) + PTREG_SAVE_GPR(27) + PTREG_SAVE_GPR(28) + PTREG_SAVE_GPR(29) + PTREG_SAVE_GPR(30) + : + PTREG_OUT_GPR(regs, 1), + PTREG_OUT_GPR(regs, 2), + PTREG_OUT_GPR(regs, 3), + PTREG_OUT_GPR(regs, 4), + PTREG_OUT_GPR(regs, 5), + PTREG_OUT_GPR(regs, 6), + PTREG_OUT_GPR(regs, 7), + PTREG_OUT_GPR(regs, 8), + PTREG_OUT_GPR(regs, 9), + PTREG_OUT_GPR(regs, 10), + PTREG_OUT_GPR(regs, 11), + PTREG_OUT_GPR(regs, 12), + PTREG_OUT_GPR(regs, 13), + PTREG_OUT_GPR(regs, 14), + PTREG_OUT_GPR(regs, 15), + PTREG_OUT_GPR(regs, 16), + PTREG_OUT_GPR(regs, 17), + PTREG_OUT_GPR(regs, 18), + PTREG_OUT_GPR(regs, 19), + PTREG_OUT_GPR(regs, 20), + PTREG_OUT_GPR(regs, 21), + PTREG_OUT_GPR(regs, 22), + PTREG_OUT_GPR(regs, 23), + PTREG_OUT_GPR(regs, 24), + PTREG_OUT_GPR(regs, 25), + PTREG_OUT_GPR(regs, 26), + PTREG_OUT_GPR(regs, 27), + PTREG_OUT_GPR(regs, 28), + PTREG_OUT_GPR(regs, 29), + PTREG_OUT_GPR(regs, 30) + : + : + "$1" + ); + + /* This is the second part, where we save the ra register. We then + * set the EPC register to the location immediately after the save + * of the ra register since that's the point at which the saved GPRs + * correspond with the actual GPRs. */ + __asm__ __volatile__ ( + PTREG_SAVE_GPR(31) + "1:\n" + " .set noat\n" + STR(PTR_LA) " $at, 1b\n" + PTREG_SAVE($at, cp0_epc) + " .set at\n" + : + PTREG_OUT_GPR(regs, 31), + PTREG_OUT(regs, cp0_epc, cp0_epc) + : + : + "$1" + ); + + /* The zero register is always, well, zero. */ + regs->regs[0] = 0; + + /* Grab the values of the coprocessor zero Status and Cause registers. + * We haven't done anything that will affect them up to this point, + * so waiting until here to save them is a reasonable thing to do. */ + regs->cp0_status = read_c0_status(); + regs->cp0_cause = read_c0_cause(); + + return regs; +} #endif #endif /* _ASM_PTRACE_H */ -- To unsubscribe from this list: send the line "unsubscribe linux-arch" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html