1/*- 2 * Copyright (c) 2005 Antoine Brodin 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include <sys/types.h> 31#include <sys/systm.h> 32#include <sys/param.h> 33#include <sys/proc.h> 34#include <sys/stack.h> 35 36#include <machine/mips_opcode.h> 37 38#include <machine/param.h> 39#include <machine/pcb.h> 40#include <machine/regnum.h> 41 42static u_register_t 43stack_register_fetch(u_register_t sp, u_register_t stack_pos) 44{ 45 u_register_t * stack = 46 ((u_register_t *)(intptr_t)sp + (size_t)stack_pos/sizeof(u_register_t)); 47 48 return *stack; 49} 50 51static void 52stack_capture(struct stack *st, u_register_t pc, u_register_t sp) 53{ 54 u_register_t ra = 0, i, stacksize; 55 short ra_stack_pos = 0; 56 InstFmt insn; 57 58 stack_zero(st); 59 60 for (;;) { 61 stacksize = 0; 62 if (pc <= (u_register_t)(intptr_t)btext) 63 break; 64 for (i = pc; i >= (u_register_t)(intptr_t)btext; i -= sizeof (insn)) { 65 bcopy((void *)(intptr_t)i, &insn, sizeof insn); 66 switch (insn.IType.op) { 67 case OP_ADDI: 68 case OP_ADDIU: 69 case OP_DADDI: 70 case OP_DADDIU: 71 if (insn.IType.rs != SP || insn.IType.rt != SP) 72 break; 73 stacksize = -(short)insn.IType.imm; 74 break; 75 76 case OP_SW: 77 case OP_SD: 78 if (insn.IType.rs != SP || insn.IType.rt != RA) 79 break; 80 ra_stack_pos = (short)insn.IType.imm; 81 break; 82 default: 83 break; 84 } 85 86 if (stacksize) 87 break; 88 } 89 90 if (stack_put(st, pc) == -1) 91 break; 92 93 for (i = pc; !ra; i += sizeof (insn)) { 94 bcopy((void *)(intptr_t)i, &insn, sizeof insn); 95 96 switch (insn.IType.op) { 97 case OP_SPECIAL: 98 if((insn.RType.func == OP_JR)) 99 { 100 if (ra >= (u_register_t)(intptr_t)btext) 101 break; 102 if (insn.RType.rs != RA) 103 break; 104 ra = stack_register_fetch(sp, 105 ra_stack_pos); 106 if (!ra) 107 goto done; 108 ra -= 8; 109 } 110 break; 111 default: 112 break; 113 } 114 /* eret */ 115 if (insn.word == 0x42000018) 116 goto done; 117 } 118 119 if (pc == ra && stacksize == 0) 120 break; 121 122 sp += stacksize; 123 pc = ra; 124 ra = 0; 125 } 126done: 127 return; 128} 129 130void 131stack_save_td(struct stack *st, struct thread *td) 132{ 133 u_register_t pc, sp; 134 135 if (TD_IS_SWAPPED(td)) 136 panic("stack_save_td: swapped"); 137 if (TD_IS_RUNNING(td)) 138 panic("stack_save_td: running"); 139 140 pc = td->td_pcb->pcb_regs.pc; 141 sp = td->td_pcb->pcb_regs.sp; 142 stack_capture(st, pc, sp); 143} 144 145void 146stack_save(struct stack *st) 147{ 148 u_register_t pc, sp; 149 150 if (curthread == NULL) 151 panic("stack_save: curthread == NULL"); 152 153 pc = curthread->td_pcb->pcb_regs.pc; 154 sp = curthread->td_pcb->pcb_regs.sp; 155 stack_capture(st, pc, sp); 156} 157