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