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