PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
callstack.c
1/*
2 * $Xorg: getretmips.c,v 1.4 2001/02/09 02:06:19 xorgcvs Exp $
3 *
4Copyright 1992, 1998 The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25 *
26 * Author: Keith Packard, MIT X Consortium
27 * cleaned up slighly by emoon and added ee related opcodes and checking.
28 */
29
30/* Return stack generation for MIPS processors
31 * This is tricky as MIPS stack frames aren't
32 * easily unrolled -- we look for pc restoration
33 * and stack adjustment instructions beyond the return
34 * address to discover the correct values
35 */
36
37/* lw $31,const($sp) is : 100 011 11101 11111 const */
38/* 1000 1111 1011 1111 */
39
40#define RESTORE_RETURNVAL 0x8fbf0000
41#define RESTORE_RETURNVAL_MASK 0xffff0000
42
43/* ld $31,const($sp) is : 110 111 11101 11111 const */
44/* 1101 1111 1011 1111 */
45
46#define RESTORE_RETURNVAL2 0xdfbf0000
47
48/* lq $31,const($sp) is : 011110 11101 11111 const */
49/* ee Related 0111 1011 1011 1111 */
50
51#define RESTORE_RETURNVAL3 0x7bbf0000
52
53/* addiu $sp, $sp, const is 001 001 11101 11101 const */
54/* 0010 0111 1011 1101 const */
55
56#define ADJUST_STACKP_C 0x27bd0000
57#define ADJUST_STACKP_C_MASK 0xffff0000
58
59/* addu $sp, $sp, $at is 000 000 11101 00001 11101 00000 100 001 */
60/* 0000 0011 1010 0001 1110 1000 0010 0001 */
61
62#define ADJUST_STACKP_V 0x03a1e821
63#define ADJUST_STACKP_V_MASK 0xffffffff
64
65/* lui $at, const is 001 111 00000 00001 const */
66/* 0011 1100 0000 0001 const */
67
68#define SET_UPPER_C 0x3c010000
69#define SET_UPPER_C_MASK 0xffff0000
70
71/* ori $at, $at, const is 001 101 00001 00001 const */
72/* 0011 0100 0010 0001 const */
73
74#define OR_LOWER_C 0x34210000
75#define OR_LOWER_C_MASK 0xffff0000
76
77/* ori $at, $zero, const is 001 101 00000 00001 const */
78/* 0011 0100 0000 0001 const */
79
80#define SET_LOWER_C 0x34010000
81#define SET_LOWER_C_MASK 0xffff0000
82
83/* jr $ra */
84#define RETURN 0x03e00008
85
86#define CALL(f) (0x0c000000 | (((int) (f)) >> 2))
87
88/*
89 * This computation is expensive, so we cache the results;
90 * a simple hash function and straight-forward replacement.
91 */
92
93#define HASH_SIZE 256
94
95typedef struct _returnCache
96{
97 unsigned int *returnAddress;
98 int raOffset;
99 int spAdjust;
101
102static ReturnCacheRec returnCache[HASH_SIZE];
103
104#define HASH(ra) ((((int) (ra)) >> 2) & (HASH_SIZE - 1))
105
106typedef int Bool;
107
108#ifndef TRUE
109#define TRUE 1
110#endif
111#ifndef FALSE
112#define FALSE 0
113#endif
114
115extern unsigned int* ps2GetReturnAddress();
116extern unsigned int* ps2GetStackPointer();
117extern int main();
118
119void ps2GetStackTrace(unsigned int* results,int max)
120{
121 unsigned int* ra;
122 unsigned int* ra_limit;
123 unsigned int* sp;
124 unsigned int inst;
125 unsigned int mainCall;
126 unsigned short const_upper;
127 unsigned short const_lower;
128 int ra_offset;
129 int sp_adjust;
130 Bool found_ra_offset, found_sp_adjust;
131 Bool found_const_upper, found_const_lower;
132
133 ra = ps2GetReturnAddress();
134 sp = ps2GetStackPointer();
135 mainCall = CALL(main);
136
137 while (ra && max)
138 {
140 rc = &returnCache[HASH(ra)];
141 if (rc->returnAddress != ra)
142 {
143 found_ra_offset = FALSE;
144 found_sp_adjust = FALSE;
145 found_const_upper = FALSE;
146 found_const_lower = FALSE;
147 const_upper = 0;
148 const_lower = 0;
149 rc->returnAddress = ra;
150 ra_limit = (unsigned int *) 0x200000;
151 ra_offset = 0;
152 sp_adjust = -1;
153
154 while ((!found_ra_offset || !found_sp_adjust) && ra < ra_limit)
155 {
156 inst = *ra;
157 /* look for the offset of the PC in the stack frame */
158 if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL)
159 {
160 ra_offset = inst & ~RESTORE_RETURNVAL_MASK;
161 found_ra_offset = TRUE;
162 }
163 else if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL2)
164 {
165 ra_offset = inst & ~RESTORE_RETURNVAL_MASK;
166 found_ra_offset = TRUE;
167 }
168 else if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL3)
169 {
170 ra_offset = inst & ~RESTORE_RETURNVAL_MASK;
171 found_ra_offset = TRUE;
172 }
173 else if ((inst & ADJUST_STACKP_C_MASK) == ADJUST_STACKP_C)
174 {
175 sp_adjust = inst & ~ADJUST_STACKP_C_MASK;
176 found_sp_adjust = TRUE;
177 }
178 else if ((inst & ADJUST_STACKP_V_MASK) == ADJUST_STACKP_V)
179 {
180 sp_adjust = 0;
181 found_sp_adjust = TRUE;
182 }
183 else if ((inst & SET_UPPER_C_MASK) == SET_UPPER_C)
184 {
185 const_upper = inst & ~SET_UPPER_C_MASK;
186 const_lower = 0;
187 found_const_upper = TRUE;
188 }
189 else if ((inst & OR_LOWER_C_MASK) == OR_LOWER_C)
190 {
191 const_lower = inst & ~OR_LOWER_C_MASK;
192 found_const_lower = TRUE;
193 }
194 else if ((inst & SET_LOWER_C_MASK) == SET_LOWER_C)
195 {
196 const_lower = inst & ~SET_LOWER_C_MASK;
197 const_upper = 0;
198 found_const_lower = TRUE;
199 }
200 else if (inst == RETURN)
201 ra_limit = ra + 2;
202 ra++;
203 }
204
205 if (sp_adjust == 0 && (found_const_upper || found_const_lower))
206 sp_adjust = (const_upper << 16) | const_lower;
207 rc->raOffset = ra_offset;
208 rc->spAdjust = sp_adjust;
209 }
210 /* if something went wrong, punt */
211 if (rc->spAdjust <= 0)
212 {
213 *results++ = 0;
214 break;
215 }
216
217 ra = (unsigned int *) sp[rc->raOffset>>2];
218 sp += rc->spAdjust >> 2;
219
220 if (ra == 0)
221 {
222 *results++ = 0;
223 break;
224 }
225
226 *results++ = ((unsigned int) ra) - 8;
227 if (ra[-2] == mainCall)
228 {
229 *results++ = 0;
230 break;
231 }
232 max--;
233 }
234}
235