diff options
Diffstat (limited to 'nx-X11/util/memleak/getretmips.c')
-rw-r--r-- | nx-X11/util/memleak/getretmips.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/nx-X11/util/memleak/getretmips.c b/nx-X11/util/memleak/getretmips.c new file mode 100644 index 000000000..3b89c6f51 --- /dev/null +++ b/nx-X11/util/memleak/getretmips.c @@ -0,0 +1,198 @@ +/* + * $Xorg: getretmips.c,v 1.4 2001/02/09 02:06:19 xorgcvs Exp $ + * +Copyright 1992, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Keith Packard, MIT X Consortium + */ + +/* Return stack generation for MIPS processors + * This is tricky as MIPS stack frames aren't + * easily unrolled -- we look for pc restoration + * and stack adjustment instructions beyond the return + * address to discover the correct values + */ + +/* lw $31,const($sp) is : 100 011 11101 11111 const */ +/* 1000 1111 1011 1111 */ + +#define RESTORE_RETURNVAL 0x8fbf0000 +#define RESTORE_RETURNVAL_MASK 0xffff0000 + +/* addiu $sp, $sp, const is 001 001 11101 11101 const */ +/* 0010 0111 1011 1101 const */ + +#define ADJUST_STACKP_C 0x27bd0000 +#define ADJUST_STACKP_C_MASK 0xffff0000 + +/* addu $sp, $sp, $at is 000 000 11101 00001 11101 00000 100 001 */ +/* 0000 0011 1010 0001 1110 1000 0010 0001 */ + +#define ADJUST_STACKP_V 0x03a1e821 +#define ADJUST_STACKP_V_MASK 0xffffffff + +/* lui $at, const is 001 111 00000 00001 const */ +/* 0011 1100 0000 0001 const */ + +#define SET_UPPER_C 0x3c010000 +#define SET_UPPER_C_MASK 0xffff0000 + +/* ori $at, $at, const is 001 101 00001 00001 const */ +/* 0011 0100 0010 0001 const */ + +#define OR_LOWER_C 0x34210000 +#define OR_LOWER_C_MASK 0xffff0000 + +/* ori $at, $zero, const is 001 101 00000 00001 const */ +/* 0011 0100 0000 0001 const */ + +#define SET_LOWER_C 0x34010000 +#define SET_LOWER_C_MASK 0xffff0000 + +/* jr $ra */ +#define RETURN 0x03e00008 + +#define CALL(f) (0x0c000000 | (((int) (f)) >> 2)) + +/* + * This computation is expensive, so we cache the results; + * a simple hash function and straight-forward replacement. + */ + +#define HASH_SIZE 256 + +typedef struct _returnCache { + unsigned long *returnAddress; + long raOffset; + long spAdjust; +} ReturnCacheRec, *ReturnCachePtr; + +static ReturnCacheRec returnCache[HASH_SIZE]; + +#define HASH(ra) ((((int) (ra)) >> 2) & (HASH_SIZE - 1)) + +typedef int Bool; + +#define TRUE 1 +#define FALSE 0 + +getStackTrace (results, max) + unsigned long *results; + int max; +{ + extern unsigned long *getReturnAddress (), *getStackPointer (); + extern int main (); + unsigned long *ra, *ra_limit; + unsigned long *sp; + unsigned long inst; + unsigned long mainCall; + unsigned short const_upper; + unsigned short const_lower; + long ra_offset; + long sp_adjust; + Bool found_ra_offset, found_sp_adjust; + Bool found_const_upper, found_const_lower; + ReturnCachePtr rc; + + ra = getReturnAddress (); + sp = getStackPointer (); + mainCall = CALL(main); + while (ra && max) { + rc = &returnCache[HASH(ra)]; + if (rc->returnAddress != ra) + { + found_ra_offset = FALSE; + found_sp_adjust = FALSE; + found_const_upper = FALSE; + found_const_lower = FALSE; + const_upper = 0; + const_lower = 0; + rc->returnAddress = ra; + ra_limit = (unsigned long *) 0x10000000; + ra_offset = 0; + sp_adjust = -1; + while ((!found_ra_offset || !found_sp_adjust) && ra < ra_limit) + { + inst = *ra; + /* look for the offset of the PC in the stack frame */ + if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL) + { + ra_offset = inst & ~RESTORE_RETURNVAL_MASK; + found_ra_offset = TRUE; + } + else if ((inst & ADJUST_STACKP_C_MASK) == ADJUST_STACKP_C) + { + sp_adjust = inst & ~ADJUST_STACKP_C_MASK; + found_sp_adjust = TRUE; + } + else if ((inst & ADJUST_STACKP_V_MASK) == ADJUST_STACKP_V) + { + sp_adjust = 0; + found_sp_adjust = TRUE; + } + else if ((inst & SET_UPPER_C_MASK) == SET_UPPER_C) + { + const_upper = inst & ~SET_UPPER_C_MASK; + const_lower = 0; + found_const_upper = TRUE; + } + else if ((inst & OR_LOWER_C_MASK) == OR_LOWER_C) + { + const_lower = inst & ~OR_LOWER_C_MASK; + found_const_lower = TRUE; + } + else if ((inst & SET_LOWER_C_MASK) == SET_LOWER_C) + { + const_lower = inst & ~SET_LOWER_C_MASK; + const_upper = 0; + found_const_lower = TRUE; + } + else if (inst == RETURN) + ra_limit = ra + 2; + ra++; + } + if (sp_adjust == 0 && (found_const_upper || found_const_lower)) + sp_adjust = (const_upper << 16) | const_lower; + rc->raOffset = ra_offset; + rc->spAdjust = sp_adjust; + } + /* if something went wrong, punt */ + if (rc->spAdjust <= 0) + { + *results++ = 0; + break; + } + ra = (unsigned long *) sp[rc->raOffset>>2]; + sp += rc->spAdjust >> 2; + if (ra[-2] == mainCall) + { + *results++ = 0; + break; + } + else + { + *results++ = ((unsigned long) ra) - 8; + } + max--; + } +} |