📄 stack.c
字号:
/* * mpatrol * A library for controlling and tracing dynamic memory allocations. * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307, USA. *//* * Call stacks. The method for traversing a function call stack is * dependent on both the operating system and processor architecture. * The most correct way of doing this would be to perform code-reading * in order to ascertain the return address for a function. However, * some operating systems provide support functions for doing this. */#include "stack.h"#include "memory.h"#include "machine.h"#include <string.h>#if !MP_BUILTINSTACK_SUPPORT#if MP_LIBRARYSTACK_SUPPORT#if TARGET == TARGET_UNIX#if SYSTEM == SYSTEM_IRIX#include <exception.h>#include <ucontext.h>#elif SYSTEM == SYSTEM_TRU64#include <excpt.h>#endif /* SYSTEM */#elif TARGET == TARGET_WINDOWS#include <setjmp.h>#endif /* TARGET */#else /* MP_LIBRARYSTACK_SUPPORT */#if TARGET == TARGET_UNIX#include <setjmp.h>#if MP_SIGINFO_SUPPORT#include <siginfo.h>#endif /* MP_SIGINFO_SUPPORT */#if SYSTEM == SYSTEM_DRSNX || SYSTEM == SYSTEM_SOLARIS#if ARCH == ARCH_SPARC#include <ucontext.h>#ifndef R_SP#define R_SP REG_SP#endif /* R_SP */#endif /* ARCH */#endif /* SYSTEM */#endif /* TARGET */#endif /* MP_LIBRARYSTACK_SUPPORT */#endif /* MP_BUILTINSTACK_SUPPORT */#if MP_IDENT_SUPPORT#ident "$Id: stack.c,v 1.30 2002/01/08 20:13:59 graeme Exp $"#else /* MP_IDENT_SUPPORT */static MP_CONST MP_VOLATILE char *stack_id = "$Id: stack.c,v 1.30 2002/01/08 20:13:59 graeme Exp $";#endif /* MP_IDENT_SUPPORT */#if MP_BUILTINSTACK_SUPPORT/* This method of call stack traversal uses two special builtin functions in * gcc called __builtin_frame_address() and __builtin_return_address(). Both * of these functions take the number of stack frames to traverse as a parameter * but this must currently be a constant, hence the reason for all of the * following complicated macros, and for the fact that there must currently * be a maximum number of stack frames to traverse that is determined at compile * time. However, it may be the case that this method is slightly better than * manually traversing the call stack. Perhaps in the future gcc might allow * these functions to accept non-constant parameters... */#define frameaddress(v, n) (v[n] = __builtin_frame_address(n))#define frameaddress1(v) frameaddress(v, 0)#define frameaddress2(v) frameaddress1(v) && frameaddress(v, 1)#define frameaddress3(v) frameaddress2(v) && frameaddress(v, 2)#define frameaddress4(v) frameaddress3(v) && frameaddress(v, 3)#define frameaddress5(v) frameaddress4(v) && frameaddress(v, 4)#define frameaddress6(v) frameaddress5(v) && frameaddress(v, 5)#define frameaddress7(v) frameaddress6(v) && frameaddress(v, 6)#define frameaddress8(v) frameaddress7(v) && frameaddress(v, 7)#define frameaddressn(v, w, n) if (frameaddress ## n(v)) \ w = __builtin_frame_address(n)#define frameaddresses(v, w, n) frameaddressn(v, w, n)#define returnaddress(v, n) (v[n] = __builtin_return_address(n))#define returnaddress1(v) returnaddress(v, 0)#define returnaddress2(v) returnaddress1(v) && returnaddress(v, 1)#define returnaddress3(v) returnaddress2(v) && returnaddress(v, 2)#define returnaddress4(v) returnaddress3(v) && returnaddress(v, 3)#define returnaddress5(v) returnaddress4(v) && returnaddress(v, 4)#define returnaddress6(v) returnaddress5(v) && returnaddress(v, 5)#define returnaddress7(v) returnaddress6(v) && returnaddress(v, 6)#define returnaddress8(v) returnaddress7(v) && returnaddress(v, 7)#define returnaddressn(v, w, n) if (returnaddress ## n(v)) \ w = __builtin_return_address(n)#define returnaddresses(v, w, n) returnaddressn(v, w, n)#if MP_MAXSTACK > 8#error not enough frameaddress() and returnaddress() macros#endif /* MP_MAXSTACK */#elif !MP_LIBRARYSTACK_SUPPORT#if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS/* These macros are used by the unwind() function for setting flags when * certain instructions are seen. */#define RA_OFFSET 1 /* return address offset has been set */#define SP_OFFSET 2 /* stack pointer offset has been set */#define SP_LOWER 4 /* lower part of stack pointer offset has been set */#define SP_UPPER 8 /* upper part of stack pointer offset has been set */#endif /* TARGET && ARCH */#endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */#ifdef __cplusplusextern "C"{#endif /* __cplusplus */#if !MP_BUILTINSTACK_SUPPORT && TARGET == TARGET_UNIX#if MP_LIBRARYSTACK_SUPPORT#if SYSTEM == SYSTEM_HPUX/* The following function is defined in the HP/UX traceback library (libcl). */int U_get_previous_frame(frameinfo *, frameinfo *);#elif SYSTEM == SYSTEM_IRIX || SYSTEM == SYSTEM_TRU64/* The unwind() function in the IRIX and Tru64 exception-handling libraries * (libexc) may call malloc() and several memory operation functions, so we * need to guard against this by preventing recursive calls. */static unsigned char recursive;#if SYSTEM == SYSTEM_TRU64MP_API char *__mp_symbol(void *);#endif /* SYSTEM */#endif /* SYSTEM */#else /* MP_LIBRARYSTACK_SUPPORT */static jmp_buf environment;#if MP_SIGINFO_SUPPORTstatic struct sigaction bushandler;static struct sigaction segvhandler;#else /* MP_SIGINFO_SUPPORT */static void (*bushandler)(int);static void (*segvhandler)(int);#endif /* MP_SIGINFO_SUPPORT */#endif /* MP_LIBRARYSTACK_SUPPORT */#endif /* MP_BUILTINSTACK_SUPPORT && TARGET *//* Initialise the fields of a stackinfo structure. */MP_GLOBALvoid__mp_newframe(stackinfo *s, void *f){ s->frame = s->addr = NULL;#if MP_BUILTINSTACK_SUPPORT for (s->index = 0; s->index < MP_MAXSTACK; s->index++) s->frames[s->index] = s->addrs[s->index] = NULL; s->index = 0;#elif MP_LIBRARYSTACK_SUPPORT#if TARGET == TARGET_UNIX#if SYSTEM == SYSTEM_HPUX __mp_memset(&s->next, 0, sizeof(frameinfo));#elif SYSTEM == SYSTEM_IRIX || SYSTEM == SYSTEM_TRU64 __mp_memset(&s->next, 0, sizeof(struct sigcontext));#endif /* SYSTEM */#elif TARGET == TARGET_WINDOWS __mp_memset(&s->next, 0, sizeof(STACKFRAME));#endif /* TARGET */#else /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */#if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS s->next.sp = s->next.ra = 0;#else /* TARGET && ARCH */ s->next = NULL;#endif /* TARGET && ARCH */#endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */ s->first = f;}#if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT && \ TARGET == TARGET_UNIX/* Handles any signals that result from illegal memory accesses whilst * traversing the call stack. */staticvoidstackhandler(int s){ longjmp(environment, 1);}#endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT && TARGET */#if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT#if (TARGET == TARGET_UNIX && (ARCH == ARCH_IX86 || ARCH == ARCH_M68K || \ ARCH == ARCH_M88K || ARCH == ARCH_POWER || ARCH == ARCH_POWERPC || \ ARCH == ARCH_SPARC)) || ((TARGET == TARGET_WINDOWS || \ TARGET == TARGET_NETWARE) && ARCH == ARCH_IX86)/* Obtain the return address for the specified stack frame handle. */staticunsigned long *getaddr(unsigned long *p){ unsigned long *a; /* This function relies heavily on the stack frame format of supported * OS / processor combinations. A better way to determine the return * address would be to perform code reading, but on CISC processors this * could be a nightmare. */#if ARCH == ARCH_IX86 || ARCH == ARCH_M68K || ARCH == ARCH_M88K a = (unsigned long *) *(p + 1);#elif ARCH == ARCH_POWER || ARCH == ARCH_POWERPC a = (unsigned long *) *(p + 2);#elif ARCH == ARCH_SPARC if (*p == 0) a = NULL;#if ENVIRON == ENVIRON_64 else if (a = (unsigned long *) *((unsigned long *) (*p + 0x7FF) + 15))#else /* ENVIRON */ else if (a = (unsigned long *) *((unsigned long *) *p + 15))#endif /* ENVIRON */ a += 2;#endif /* ARCH */ return a;}#endif /* TARGET && ARCH */#endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */#if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT#if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS/* Determine the stack pointer and return address of the previous stack frame * by performing code reading. */staticintunwind(frameinfo *f){ long p, s; unsigned long a, i, q; unsigned short l, u; s = -1; p = 0; q = 0xFFFFFFFF; l = u = 0; a = 0; /* Determine the current stack pointer and return address if we are * initiating call stack traversal. */ if (f->ra == 0) { f->sp = __mp_stackpointer(); f->ra = __mp_returnaddress(); } /* Search for the return address offset in the stack frame. */ while (!((a & RA_OFFSET) && (a & SP_OFFSET)) && (f->ra < q)) { i = *((unsigned long *) f->ra); if (i == 0x03E00008) { /* jr ra */ q = f->ra + 8; } else if (i == 0x03A1E821) { /* addu sp,sp,at */ s = 0; a |= SP_OFFSET; } else switch (i >> 16) { case 0x27BD: /* addiu sp,sp,## */ s = i & 0xFFFF; a |= SP_OFFSET; break; case 0x3401: /* ori at,zero,## */ l = i & 0xFFFF; u = 0; a |= SP_LOWER; break; case 0x3421: /* ori at,at,## */ l = i & 0xFFFF; a |= SP_LOWER; break; case 0x3C01: /* lui at,## */ l = 0; u = i & 0xFFFF; a |= SP_UPPER; break; case 0x8FBF: /* lw ra,##(sp) */ p = i & 0xFFFF; a |= RA_OFFSET; break; } f->ra += 4; } if ((s == 0) && ((a & SP_LOWER) || (a & SP_UPPER))) s = (u << 16) | l; if ((s > 0) && (i = ((unsigned long *) f->sp)[p >> 2]) && ((*((unsigned long *) (i - 8)) == 0x0320F809) || (*((unsigned long *) (i - 8)) >> 16 == 0x0C10))) { /* jalr ra,t9 or jal ## */ f->sp += s; f->ra = i; return 1; } f->sp = f->ra = 0; return 0;}#endif /* TARGET && ARCH */#endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */#if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT && \ TARGET == TARGET_UNIX#if ARCH == ARCH_SPARC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -