1 /*
2  * mpatrol
3  * A library for controlling and tracing dynamic memory allocations.
4  * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307, USA.
20  */
21 
22 
23 /*
24  * Call stacks.  The method for traversing a function call stack is
25  * dependent on both the operating system and processor architecture.
26  * The most correct way of doing this would be to perform code-reading
27  * in order to ascertain the return address for a function.  However,
28  * some operating systems provide support functions for doing this.
29  */
30 
31 
32 #include "stack.h"
33 #include "memory.h"
34 #include "machine.h"
35 #include <string.h>
36 #if !MP_BUILTINSTACK_SUPPORT
37 #if MP_LIBRARYSTACK_SUPPORT
38 #if TARGET == TARGET_UNIX
39 #if SYSTEM == SYSTEM_IRIX
40 #include <exception.h>
41 #include <ucontext.h>
42 #elif SYSTEM == SYSTEM_TRU64
43 #include <excpt.h>
44 #endif /* SYSTEM */
45 #elif TARGET == TARGET_WINDOWS
46 #include <setjmp.h>
47 #endif /* TARGET */
48 #else /* MP_LIBRARYSTACK_SUPPORT */
49 #if TARGET == TARGET_UNIX
50 #include <setjmp.h>
51 #if MP_SIGINFO_SUPPORT
52 #include <siginfo.h>
53 #endif /* MP_SIGINFO_SUPPORT */
54 #if SYSTEM == SYSTEM_DRSNX || SYSTEM == SYSTEM_SOLARIS
55 #if ARCH == ARCH_SPARC
56 #include <ucontext.h>
57 #ifndef R_SP
58 #define R_SP REG_SP
59 #endif /* R_SP */
60 #endif /* ARCH */
61 #endif /* SYSTEM */
62 #endif /* TARGET */
63 #endif /* MP_LIBRARYSTACK_SUPPORT */
64 #endif /* MP_BUILTINSTACK_SUPPORT */
65 
66 
67 #if MP_IDENT_SUPPORT
68 #ident "$Id: stack.c,v 1.30 2002/01/08 20:13:59 graeme Exp $"
69 #else /* MP_IDENT_SUPPORT */
70 static MP_CONST MP_VOLATILE char *stack_id = "$Id: stack.c,v 1.30 2002/01/08 20:13:59 graeme Exp $";
71 #endif /* MP_IDENT_SUPPORT */
72 
73 
74 #if MP_BUILTINSTACK_SUPPORT
75 /* This method of call stack traversal uses two special builtin functions in
76  * gcc called __builtin_frame_address() and __builtin_return_address().  Both
77  * of these functions take the number of stack frames to traverse as a parameter
78  * but this must currently be a constant, hence the reason for all of the
79  * following complicated macros, and for the fact that there must currently
80  * be a maximum number of stack frames to traverse that is determined at compile
81  * time.  However, it may be the case that this method is slightly better than
82  * manually traversing the call stack.  Perhaps in the future gcc might allow
83  * these functions to accept non-constant parameters...
84  */
85 
86 #define frameaddress(v, n) (v[n] = __builtin_frame_address(n))
87 #define frameaddress1(v) frameaddress(v, 0)
88 #define frameaddress2(v) frameaddress1(v) && frameaddress(v, 1)
89 #define frameaddress3(v) frameaddress2(v) && frameaddress(v, 2)
90 #define frameaddress4(v) frameaddress3(v) && frameaddress(v, 3)
91 #define frameaddress5(v) frameaddress4(v) && frameaddress(v, 4)
92 #define frameaddress6(v) frameaddress5(v) && frameaddress(v, 5)
93 #define frameaddress7(v) frameaddress6(v) && frameaddress(v, 6)
94 #define frameaddress8(v) frameaddress7(v) && frameaddress(v, 7)
95 #define frameaddressn(v, w, n) if (frameaddress ## n(v)) \
96                                    w = __builtin_frame_address(n)
97 #define frameaddresses(v, w, n) frameaddressn(v, w, n)
98 
99 #define returnaddress(v, n) (v[n] = __builtin_return_address(n))
100 #define returnaddress1(v) returnaddress(v, 0)
101 #define returnaddress2(v) returnaddress1(v) && returnaddress(v, 1)
102 #define returnaddress3(v) returnaddress2(v) && returnaddress(v, 2)
103 #define returnaddress4(v) returnaddress3(v) && returnaddress(v, 3)
104 #define returnaddress5(v) returnaddress4(v) && returnaddress(v, 4)
105 #define returnaddress6(v) returnaddress5(v) && returnaddress(v, 5)
106 #define returnaddress7(v) returnaddress6(v) && returnaddress(v, 6)
107 #define returnaddress8(v) returnaddress7(v) && returnaddress(v, 7)
108 #define returnaddressn(v, w, n) if (returnaddress ## n(v)) \
109                                     w = __builtin_return_address(n)
110 #define returnaddresses(v, w, n) returnaddressn(v, w, n)
111 
112 #if MP_MAXSTACK > 8
113 #error not enough frameaddress() and returnaddress() macros
114 #endif /* MP_MAXSTACK */
115 #elif !MP_LIBRARYSTACK_SUPPORT
116 #if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS
117 /* These macros are used by the unwind() function for setting flags when
118  * certain instructions are seen.
119  */
120 
121 #define RA_OFFSET 1 /* return address offset has been set */
122 #define SP_OFFSET 2 /* stack pointer offset has been set */
123 #define SP_LOWER  4 /* lower part of stack pointer offset has been set */
124 #define SP_UPPER  8 /* upper part of stack pointer offset has been set */
125 #endif /* TARGET && ARCH */
126 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
127 
128 
129 #ifdef __cplusplus
130 extern "C"
131 {
132 #endif /* __cplusplus */
133 
134 
135 #if !MP_BUILTINSTACK_SUPPORT && TARGET == TARGET_UNIX
136 #if MP_LIBRARYSTACK_SUPPORT
137 #if SYSTEM == SYSTEM_HPUX
138 /* The following function is defined in the HP/UX traceback library (libcl).
139  */
140 
141 int U_get_previous_frame(frameinfo *, frameinfo *);
142 #elif SYSTEM == SYSTEM_IRIX || SYSTEM == SYSTEM_TRU64
143 /* The unwind() function in the IRIX and Tru64 exception-handling libraries
144  * (libexc) may call malloc() and several memory operation functions, so we
145  * need to guard against this by preventing recursive calls.
146  */
147 
148 static unsigned char recursive;
149 
150 #if SYSTEM == SYSTEM_TRU64
151 MP_API char *__mp_symbol(void *);
152 #endif /* SYSTEM */
153 #endif /* SYSTEM */
154 #else /* MP_LIBRARYSTACK_SUPPORT */
155 static jmp_buf environment;
156 #if MP_SIGINFO_SUPPORT
157 static struct sigaction bushandler;
158 static struct sigaction segvhandler;
159 #else /* MP_SIGINFO_SUPPORT */
160 static void (*bushandler)(int);
161 static void (*segvhandler)(int);
162 #endif /* MP_SIGINFO_SUPPORT */
163 #endif /* MP_LIBRARYSTACK_SUPPORT */
164 #endif /* MP_BUILTINSTACK_SUPPORT && TARGET */
165 
166 
167 /* Initialise the fields of a stackinfo structure.
168  */
169 
170 MP_GLOBAL
171 void
__mp_newframe(stackinfo * s,void * f)172 __mp_newframe(stackinfo *s, void *f)
173 {
174     s->frame = s->addr = NULL;
175 #if MP_BUILTINSTACK_SUPPORT
176     for (s->index = 0; s->index < MP_MAXSTACK; s->index++)
177         s->frames[s->index] = s->addrs[s->index] = NULL;
178     s->index = 0;
179 #elif MP_LIBRARYSTACK_SUPPORT
180 #if TARGET == TARGET_UNIX
181 #if SYSTEM == SYSTEM_HPUX
182     __mp_memset(&s->next, 0, sizeof(frameinfo));
183 #elif SYSTEM == SYSTEM_IRIX || SYSTEM == SYSTEM_TRU64
184     __mp_memset(&s->next, 0, sizeof(struct sigcontext));
185 #endif /* SYSTEM */
186 #elif TARGET == TARGET_WINDOWS
187     __mp_memset(&s->next, 0, sizeof(STACKFRAME));
188 #endif /* TARGET */
189 #else /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
190 #if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS
191     s->next.sp = s->next.ra = 0;
192 #else /* TARGET && ARCH */
193     s->next = NULL;
194 #endif /* TARGET && ARCH */
195 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
196     s->first = f;
197 }
198 
199 
200 #if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT && \
201     TARGET == TARGET_UNIX
202 /* Handles any signals that result from illegal memory accesses whilst
203  * traversing the call stack.
204  */
205 
206 static
207 void
stackhandler(int s)208 stackhandler(int s)
209 {
210     longjmp(environment, 1);
211 }
212 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT && TARGET */
213 
214 
215 #if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT
216 #if (TARGET == TARGET_UNIX && (ARCH == ARCH_IX86 || ARCH == ARCH_M68K || \
217       ARCH == ARCH_M88K || ARCH == ARCH_POWER || ARCH == ARCH_POWERPC || \
218       ARCH == ARCH_SPARC)) || ((TARGET == TARGET_WINDOWS || \
219       TARGET == TARGET_NETWARE) && ARCH == ARCH_IX86)
220 /* Obtain the return address for the specified stack frame handle.
221  */
222 
223 static
224 unsigned long *
getaddr(unsigned long * p)225 getaddr(unsigned long *p)
226 {
227     unsigned long *a;
228 
229     /* This function relies heavily on the stack frame format of supported
230      * OS / processor combinations.  A better way to determine the return
231      * address would be to perform code reading, but on CISC processors this
232      * could be a nightmare.
233      */
234 #if ARCH == ARCH_IX86 || ARCH == ARCH_M68K || ARCH == ARCH_M88K
235     a = (unsigned long *) *(p + 1);
236 #elif ARCH == ARCH_POWER || ARCH == ARCH_POWERPC
237     a = (unsigned long *) *(p + 2);
238 #elif ARCH == ARCH_SPARC
239     if (*p == 0)
240         a = NULL;
241 #if ENVIRON == ENVIRON_64
242     else if (a = (unsigned long *) *((unsigned long *) (*p + 0x7FF) + 15))
243 #else /* ENVIRON */
244     else if (a = (unsigned long *) *((unsigned long *) *p + 15))
245 #endif /* ENVIRON */
246         a += 2;
247 #endif /* ARCH */
248     return a;
249 }
250 #endif /* TARGET && ARCH */
251 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
252 
253 
254 #if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT
255 #if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS
256 /* Determine the stack pointer and return address of the previous stack frame
257  * by performing code reading.
258  */
259 
260 static
261 int
unwind(frameinfo * f)262 unwind(frameinfo *f)
263 {
264     long p, s;
265     unsigned long a, i, q;
266     unsigned short l, u;
267 
268     s = -1;
269     p = 0;
270     q = 0xFFFFFFFF;
271     l = u = 0;
272     a = 0;
273     /* Determine the current stack pointer and return address if we are
274      * initiating call stack traversal.
275      */
276     if (f->ra == 0)
277     {
278         f->sp = __mp_stackpointer();
279         f->ra = __mp_returnaddress();
280     }
281     /* Search for the return address offset in the stack frame.
282      */
283     while (!((a & RA_OFFSET) && (a & SP_OFFSET)) && (f->ra < q))
284     {
285         i = *((unsigned long *) f->ra);
286         if (i == 0x03E00008)
287         {
288             /* jr ra */
289             q = f->ra + 8;
290         }
291         else if (i == 0x03A1E821)
292         {
293             /* addu sp,sp,at */
294             s = 0;
295             a |= SP_OFFSET;
296         }
297         else
298             switch (i >> 16)
299             {
300               case 0x27BD:
301                 /* addiu sp,sp,## */
302                 s = i & 0xFFFF;
303                 a |= SP_OFFSET;
304                 break;
305               case 0x3401:
306                 /* ori at,zero,## */
307                 l = i & 0xFFFF;
308                 u = 0;
309                 a |= SP_LOWER;
310                 break;
311               case 0x3421:
312                 /* ori at,at,## */
313                 l = i & 0xFFFF;
314                 a |= SP_LOWER;
315                 break;
316               case 0x3C01:
317                 /* lui at,## */
318                 l = 0;
319                 u = i & 0xFFFF;
320                 a |= SP_UPPER;
321                 break;
322               case 0x8FBF:
323                 /* lw ra,##(sp) */
324                 p = i & 0xFFFF;
325                 a |= RA_OFFSET;
326                 break;
327             }
328         f->ra += 4;
329     }
330     if ((s == 0) && ((a & SP_LOWER) || (a & SP_UPPER)))
331         s = (u << 16) | l;
332     if ((s > 0) && (i = ((unsigned long *) f->sp)[p >> 2]) &&
333         ((*((unsigned long *) (i - 8)) == 0x0320F809) ||
334          (*((unsigned long *) (i - 8)) >> 16 == 0x0C10)))
335     {
336         /* jalr ra,t9 or jal ## */
337         f->sp += s;
338         f->ra = i;
339         return 1;
340     }
341     f->sp = f->ra = 0;
342     return 0;
343 }
344 #endif /* TARGET && ARCH */
345 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
346 
347 
348 #if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT && \
349     TARGET == TARGET_UNIX
350 #if ARCH == ARCH_SPARC
351 /* Return a handle for the frame pointer at the current point in execution.
352  */
353 
354 static
355 unsigned long *
getframe(void)356 getframe(void)
357 {
358 #if SYSTEM == SYSTEM_DRSNX || SYSTEM == SYSTEM_SOLARIS
359     ucontext_t c;
360 #endif /* SYSTEM */
361     unsigned long a;
362 
363 #if SYSTEM == SYSTEM_DRSNX || SYSTEM == SYSTEM_SOLARIS
364     if (getcontext(&c) == -1)
365         return NULL;
366     a = c.uc_mcontext.gregs[R_SP];
367 #else /* SYSTEM */
368     a = __mp_stackpointer();
369 #endif /* SYSTEM */
370 #if ENVIRON == ENVIRON_64
371     return (unsigned long *) (a + 0x7FF) + 14;
372 #else /* ENVIRON */
373     return (unsigned long *) a + 14;
374 #endif /* ENVIRON */
375 }
376 #endif /* ARCH */
377 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT && TARGET */
378 
379 
380 /* Return a handle for the stack frame at the current point in execution
381  * or the next stack frame in the call stack.
382  */
383 
384 MP_GLOBAL
385 int
__mp_getframe(stackinfo * p)386 __mp_getframe(stackinfo *p)
387 {
388 #if MP_BUILTINSTACK_SUPPORT
389     void *f;
390 #elif MP_LIBRARYSTACK_SUPPORT
391 #if TARGET == TARGET_UNIX
392 #if SYSTEM == SYSTEM_HPUX
393     frameinfo f;
394 #elif SYSTEM == SYSTEM_TRU64
395     char *s;
396 #endif /* SYSTEM */
397 #elif TARGET == TARGET_WINDOWS
398     jmp_buf j;
399 #endif /* TARGET */
400 #else /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
401 #if MP_SIGINFO_SUPPORT
402     struct sigaction i;
403 #endif /* MP_SIGINFO_SUPPORT */
404 #if (TARGET == TARGET_UNIX && (ARCH == ARCH_IX86 || ARCH == ARCH_M68K || \
405       ARCH == ARCH_M88K || ARCH == ARCH_POWER || ARCH == ARCH_POWERPC || \
406       ARCH == ARCH_SPARC)) || ((TARGET == TARGET_WINDOWS || \
407       TARGET == TARGET_NETWARE) && ARCH == ARCH_IX86)
408     unsigned long *f;
409 #endif /* TARGET && ARCH */
410 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
411     int r;
412 
413     r = 0;
414 #if MP_BUILTINSTACK_SUPPORT
415     if (p->index == 0)
416     {
417         /* We use the macros defined above to fill in the arrays of frame
418          * pointers and return addresses.  These macros rely on the fact that
419          * if there are no more frames in the call stack then the builtin
420          * functions will return NULL.  If this is not the case then the
421          * library will crash.
422          */
423         frameaddresses(p->frames, f, MP_MAXSTACK);
424         returnaddresses(p->addrs, f, MP_MAXSTACK);
425     }
426     if ((p->index++ < MP_MAXSTACK) && (p->frame = p->frames[p->index - 1]))
427     {
428         p->addr = p->addrs[p->index - 1];
429         r = 1;
430     }
431     else
432     {
433         p->frame = NULL;
434         p->addr = NULL;
435         p->index = MP_MAXSTACK;
436     }
437 #elif MP_LIBRARYSTACK_SUPPORT
438     /* HP/UX, IRIX, Tru64 and Windows platforms provide a library for
439      * traversing function call stack frames since the stack frame format
440      * does not necessarily preserve frame pointers.  On HP/UX this is done
441      * via a special section which can be read by debuggers.
442      */
443 #if TARGET == TARGET_UNIX
444 #if SYSTEM == SYSTEM_HPUX
445     if (p->frame == NULL)
446     {
447         __mp_frameinfo(&p->next);
448         if (U_get_previous_frame(&p->next, &f) == 0)
449         {
450             p->next.size = f.size;
451             p->next.sp = f.sp;
452             p->next.ps = f.ps;
453             p->next.pc = f.pc;
454             p->next.dp = f.dp;
455         }
456         else
457             __mp_memset(&p->next, 0, sizeof(frameinfo));
458     }
459     if (p->next.pc && (U_get_previous_frame(&p->next, &f) == 0))
460     {
461         p->frame = (void *) p->next.sp;
462         p->addr = (void *) (p->next.pc & ~3);
463         p->next.size = f.size;
464         p->next.sp = f.sp;
465         p->next.ps = f.ps;
466         p->next.pc = f.pc;
467         p->next.dp = f.dp;
468         r = 1;
469     }
470     else
471     {
472         p->frame = NULL;
473         p->addr = NULL;
474     }
475 #elif SYSTEM == SYSTEM_IRIX || SYSTEM == SYSTEM_TRU64
476     /* On IRIX and Tru64, the unwind() function may call malloc(), free() and
477      * some memory operation functions every time it is invoked.  Despite the
478      * fact that we guard against recursion here, it may slow down execution to
479      * an unbearable pace, so it might be an idea to remove malloc.c from the
480      * mpatrol library if you have the option of recompiling all of your
481      * sources to include mpatrol.h.
482      */
483     if (!recursive)
484     {
485         recursive = 1;
486         if (p->frame == NULL)
487         {
488 #if SYSTEM == SYSTEM_IRIX
489             exc_setjmp(&p->next);
490 #elif SYSTEM == SYSTEM_TRU64
491             exc_capture_context(&p->next);
492 #endif /* SYSTEM */
493             unwind(&p->next, NULL);
494         }
495         if (p->next.sc_pc != 0)
496         {
497             /* On IRIX, the sigcontext structure stores registers in 64-bit
498              * format so we must be careful when converting them to 32-bit
499              * quantities.
500              */
501 #if SYSTEM == SYSTEM_IRIX
502             p->frame = (void *) p->next.sc_regs[CXT_SP];
503 #elif SYSTEM == SYSTEM_TRU64
504             p->frame = (void *) p->next.sc_regs[R_SP];
505 #endif /* SYSTEM */
506             p->addr = (void *) p->next.sc_pc;
507 #if SYSTEM == SYSTEM_TRU64
508             /* On Tru64 we cannot reliably unwind the stack from file scope
509              * initialisation or finalisation functions, or from exception-
510              * handling support functions.  Unfortunately, this means we must
511              * look at the names of the calling functions, which is likely to
512              * fail if the executable file has been stripped.
513              */
514             if (((s = __mp_symbol(p->addr)) == NULL) ||
515                 ((strncmp(s, "__INIT_00_add_", 14) != 0) &&
516                  (strncmp(s, "__FINI_00_remove_", 17) != 0) &&
517                  (strncmp(s, "__exc_add_", 10) != 0) &&
518                  (strncmp(s, "__exc_remove_", 13) != 0)))
519             {
520 #endif /* SYSTEM */
521                 unwind(&p->next, NULL);
522                 r = 1;
523 #if SYSTEM == SYSTEM_TRU64
524             }
525             else
526             {
527                 p->frame = NULL;
528                 p->addr = NULL;
529             }
530 #endif /* SYSTEM */
531         }
532         else
533         {
534             p->frame = NULL;
535             p->addr = NULL;
536         }
537         recursive = 0;
538     }
539 #endif /* SYSTEM */
540 #elif TARGET == TARGET_WINDOWS
541     if (p->frame == NULL)
542     {
543         if (p->first == NULL)
544         {
545             setjmp(j);
546             p->next.AddrPC.Offset = ((_JUMP_BUFFER *) &j)->Eip;
547             p->next.AddrFrame.Offset = ((_JUMP_BUFFER *) &j)->Ebp;
548             p->next.AddrStack.Offset = ((_JUMP_BUFFER *) &j)->Esp;
549         }
550         else
551         {
552             p->next.AddrPC.Offset = ((CONTEXT *) p->first)->Eip;
553             p->next.AddrFrame.Offset = ((CONTEXT *) p->first)->Ebp;
554             p->next.AddrStack.Offset = ((CONTEXT *) p->first)->Esp;
555         }
556         p->next.AddrPC.Mode = AddrModeFlat;
557         p->next.AddrFrame.Mode = AddrModeFlat;
558         p->next.AddrStack.Mode = AddrModeFlat;
559     }
560     if (StackWalk(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(),
561         GetCurrentThread(), &p->next, NULL, NULL, SymFunctionTableAccess,
562         SymGetModuleBase, NULL) && p->next.AddrReturn.Offset)
563     {
564         p->frame = (void *) p->next.AddrFrame.Offset;
565         p->addr = (void *) p->next.AddrReturn.Offset;
566         r = 1;
567     }
568     else
569     {
570         p->frame = NULL;
571         p->addr = NULL;
572         __mp_memset(&p->next, 0, sizeof(STACKFRAME));
573     }
574 #endif /* TARGET */
575 #else /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
576 #if (TARGET == TARGET_UNIX && (ARCH == ARCH_IX86 || ARCH == ARCH_M68K || \
577       ARCH == ARCH_M88K || ARCH == ARCH_POWER || ARCH == ARCH_POWERPC || \
578       ARCH == ARCH_SPARC)) || ((TARGET == TARGET_WINDOWS || \
579       TARGET == TARGET_NETWARE) && ARCH == ARCH_IX86)
580     /* This section is not complete in any way for the OS / processor
581      * combinations it supports, as it is intended to be as portable as possible
582      * without writing in assembler.  In particular, optimised code is likely
583      * to cause major problems for stack traversal on some platforms.
584      */
585 #if TARGET == TARGET_UNIX
586 #if MP_SIGINFO_SUPPORT
587     i.sa_flags = 0;
588     (void *) i.sa_handler = (void *) stackhandler;
589     sigfillset(&i.sa_mask);
590     sigaction(SIGBUS, &i, &bushandler);
591     sigaction(SIGSEGV, &i, &segvhandler);
592 #else /* MP_SIGINFO_SUPPORT */
593     bushandler = signal(SIGBUS, stackhandler);
594     segvhandler = signal(SIGSEGV, stackhandler);
595 #endif /* MP_SIGINFO_SUPPORT */
596     if (setjmp(environment))
597         __mp_newframe(p, p->first);
598     else
599 #endif /* TARGET */
600     {
601         if (p->frame == NULL)
602             if (p->first == NULL)
603 #if ARCH == ARCH_IX86 || ARCH == ARCH_M68K
604                 f = (unsigned long *) &p - 2;
605 #elif ARCH == ARCH_M88K
606                 f = (unsigned long *) &p - 4;
607 #elif ARCH == ARCH_POWER || ARCH == ARCH_POWERPC
608                 f = (unsigned long *) &p - 6;
609 #elif ARCH == ARCH_SPARC
610                 f = getframe();
611 #endif /* ARCH */
612             else
613                 f = (unsigned long *) p->first;
614         else
615             f = (unsigned long *) p->next;
616         if (p->frame = f)
617         {
618             p->addr = getaddr(f);
619             /* We cache the next frame pointer in the call stack since on some
620              * systems it may be overwritten by another call.
621              */
622 #if ARCH == ARCH_IX86 || ARCH == ARCH_M68K || ARCH == ARCH_M88K || \
623     ARCH == ARCH_POWER || ARCH == ARCH_POWERPC
624 #if SYSTEM == SYSTEM_LYNXOS
625             if (!getaddr((unsigned long *) *f))
626                 p->next = NULL;
627             else
628 #endif /* SYSTEM */
629                 p->next = (void *) *f;
630 #elif ARCH == ARCH_SPARC
631             if (p->addr == NULL)
632                 p->next = NULL;
633             else
634 #if ENVIRON == ENVIRON_64
635                 p->next = (void *) ((unsigned long *) (*f + 0x7FF) + 14);
636 #else /* ENVIRON */
637                 p->next = (void *) ((unsigned long *) *f + 14);
638 #endif /* ENVIRON */
639 #endif /* ARCH */
640             r = 1;
641         }
642     }
643 #if TARGET == TARGET_UNIX
644 #if MP_SIGINFO_SUPPORT
645     sigaction(SIGBUS, &bushandler, NULL);
646     sigaction(SIGSEGV, &segvhandler, NULL);
647 #else /* MP_SIGINFO_SUPPORT */
648     signal(SIGBUS, bushandler);
649     signal(SIGSEGV, segvhandler);
650 #endif /* MP_SIGINFO_SUPPORT */
651 #endif /* TARGET */
652 #elif TARGET == TARGET_UNIX && ARCH == ARCH_MIPS
653     /* For the MIPS architecture we perform code reading to determine the
654      * frame pointers and the return addresses.
655      */
656 #if MP_SIGINFO_SUPPORT
657     i.sa_flags = 0;
658     (void *) i.sa_handler = (void *) stackhandler;
659     sigfillset(&i.sa_mask);
660     sigaction(SIGBUS, &i, &bushandler);
661     sigaction(SIGSEGV, &i, &segvhandler);
662 #else /* MP_SIGINFO_SUPPORT */
663     bushandler = signal(SIGBUS, stackhandler);
664     segvhandler = signal(SIGSEGV, stackhandler);
665 #endif /* MP_SIGINFO_SUPPORT */
666     if (setjmp(environment))
667         __mp_newframe(p, p->first);
668     else
669     {
670         if (p->frame == NULL)
671             unwind(&p->next);
672         if ((p->next.ra) && unwind(&p->next))
673         {
674             p->frame = (void *) p->next.sp;
675             p->addr = (void *) (p->next.ra - 8);
676             r = 1;
677         }
678         else
679         {
680             p->frame = NULL;
681             p->addr = NULL;
682         }
683     }
684 #if MP_SIGINFO_SUPPORT
685     sigaction(SIGBUS, &bushandler, NULL);
686     sigaction(SIGSEGV, &segvhandler, NULL);
687 #else /* MP_SIGINFO_SUPPORT */
688     signal(SIGBUS, bushandler);
689     signal(SIGSEGV, segvhandler);
690 #endif /* MP_SIGINFO_SUPPORT */
691 #endif /* TARGET && ARCH */
692 #endif /* MP_BUILTINSTACK_SUPPORT && MP_LIBRARYSTACK_SUPPORT */
693     return r;
694 }
695 
696 
697 #ifdef __cplusplus
698 }
699 #endif /* __cplusplus */
700