]>
Commit | Line | Data |
---|---|---|
18744d9b BM |
1 | // backtrace.h - Fallback backtrace implementation. i386 implementation. |
2 | ||
33792684 | 3 | /* Copyright (C) 2005, 2006 Free Software Foundation |
18744d9b BM |
4 | |
5 | This file is part of libgcj. | |
6 | ||
7 | This software is copyrighted work licensed under the terms of the | |
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | #ifndef __SYSDEP_BACKTRACE_H__ | |
12 | #define __SYSDEP_BACKTRACE_H__ | |
13 | ||
14 | #include <java-stack.h> | |
15 | ||
6a92b6c7 DK |
16 | #ifdef __CYGWIN__ |
17 | /* To allow this to link as a DLL. */ | |
18 | #define MAIN_FUNC dll_crt0__FP11per_process | |
19 | extern "C" int MAIN_FUNC () __declspec(dllimport); | |
20 | #else /* !__CYGWIN__ */ | |
21 | #define MAIN_FUNC main | |
22 | extern int MAIN_FUNC (int, char **); | |
23 | #endif /* ?__CYGWIN__ */ | |
18744d9b | 24 | |
38b19a92 RM |
25 | /* The context used to keep track of our position while unwinding through |
26 | the call stack. */ | |
27 | struct _Unwind_Context | |
28 | { | |
29 | /* The starting address of the method. */ | |
30 | _Jv_uintptr_t meth_addr; | |
31 | ||
32 | /* The return address in the method. */ | |
33 | _Jv_uintptr_t ret_addr; | |
34 | }; | |
35 | ||
36 | #ifdef SJLJ_EXCEPTIONS | |
37 | ||
38 | #undef _Unwind_GetIPInfo | |
39 | #define _Unwind_GetIPInfo(ctx,ip_before_insn) \ | |
40 | (*(ip_before_insn) = 1, (ctx)->ret_addr) | |
41 | ||
42 | #undef _Unwind_GetRegionStart | |
43 | #define _Unwind_GetRegionStart(ctx) \ | |
44 | ((ctx)->meth_addr) | |
45 | ||
46 | #undef _Unwind_Backtrace | |
47 | #define _Unwind_Backtrace(trace_fn,state_ptr) \ | |
48 | (fallback_backtrace (trace_fn, state_ptr)) | |
49 | ||
50 | #endif /* SJLJ_EXCEPTIONS */ | |
51 | ||
52 | /* Unwind through the call stack calling TRACE_FN with STATE for each stack | |
53 | frame. Returns the reason why the unwinding was stopped. */ | |
54 | _Unwind_Reason_Code | |
55 | fallback_backtrace (_Unwind_Trace_Fn trace_fn, _Jv_UnwindState *state) | |
18744d9b | 56 | { |
c6d0959c RM |
57 | register _Jv_uintptr_t *_ebp __asm__ ("ebp"); |
58 | register _Jv_uintptr_t _esp __asm__ ("esp"); | |
59 | _Jv_uintptr_t rfp; | |
38b19a92 | 60 | _Unwind_Context ctx; |
18744d9b | 61 | |
38b19a92 | 62 | for (rfp = *_ebp; rfp; rfp = *(_Jv_uintptr_t *)rfp) |
18744d9b | 63 | { |
33792684 RM |
64 | /* Sanity checks to eliminate dubious-looking frame pointer chains. |
65 | The frame pointer should be a 32-bit word-aligned stack address. | |
66 | Since the stack grows downwards on x86, the frame pointer must have | |
67 | a value greater than the current value of the stack pointer, it | |
68 | should not be below the supposed next frame pointer and it should | |
69 | not be too far off from the supposed next frame pointer. */ | |
c6d0959c RM |
70 | int diff = *(_Jv_uintptr_t *)rfp - rfp; |
71 | if ((rfp & 0x00000003) != 0 || rfp < _esp | |
33792684 | 72 | || diff > 4 * 1024 || diff < 0) |
18744d9b BM |
73 | break; |
74 | ||
c6d0959c RM |
75 | /* Get the return address in the calling function. This is stored on |
76 | the stack just before the value of the old frame pointer. */ | |
38b19a92 | 77 | ctx.ret_addr = *(_Jv_uintptr_t *)(rfp + sizeof (_Jv_uintptr_t)); |
c6d0959c RM |
78 | |
79 | /* Try to locate a "pushl %ebp; movl %esp, %ebp" function prologue | |
80 | by scanning backwards at even addresses below the return address. | |
d58b0443 RM |
81 | This instruction sequence is encoded either as 0x55 0x89 0xE5 or as |
82 | 0x55 0x8B 0xEC. We give up if we do not find this sequence even | |
83 | after scanning 1024K of memory. | |
c6d0959c RM |
84 | FIXME: This is not robust and will probably give us false positives, |
85 | but this is about the best we can do if we do not have DWARF-2 unwind | |
86 | information based exception handling. */ | |
38b19a92 RM |
87 | ctx.meth_addr = (_Jv_uintptr_t)NULL; |
88 | _Jv_uintptr_t scan_addr = (ctx.ret_addr & 0xFFFFFFFE) - 2; | |
c6d0959c RM |
89 | _Jv_uintptr_t limit_addr |
90 | = (scan_addr > 1024 * 1024) ? (scan_addr - 1024 * 1024) : 2; | |
91 | for ( ; scan_addr >= limit_addr; scan_addr -= 2) | |
33792684 | 92 | { |
c6d0959c | 93 | unsigned char *scan_bytes = (unsigned char *)scan_addr; |
d58b0443 RM |
94 | if (scan_bytes[0] == 0x55 |
95 | && ((scan_bytes[1] == 0x89 && scan_bytes[2] == 0xE5) | |
96 | || (scan_bytes[1] == 0x8B && scan_bytes[2] == 0xEC))) | |
c6d0959c | 97 | { |
38b19a92 | 98 | ctx.meth_addr = scan_addr; |
c6d0959c RM |
99 | break; |
100 | } | |
33792684 RM |
101 | } |
102 | ||
38b19a92 RM |
103 | /* Now call the unwinder callback function. */ |
104 | if (trace_fn != NULL) | |
105 | (*trace_fn) (&ctx, state); | |
33792684 | 106 | |
38b19a92 RM |
107 | /* No need to unwind beyond _Jv_RunMain(), _Jv_ThreadStart or |
108 | main(). */ | |
109 | void *jv_runmain | |
110 | = (void *)(void (*)(JvVMInitArgs *, jclass, const char *, int, | |
111 | const char **, bool))_Jv_RunMain; | |
112 | if (ctx.meth_addr == (_Jv_uintptr_t)jv_runmain | |
113 | || ctx.meth_addr == (_Jv_uintptr_t)_Jv_ThreadStart | |
6a92b6c7 | 114 | || (ctx.meth_addr - (_Jv_uintptr_t)MAIN_FUNC) < 16) |
38b19a92 | 115 | break; |
18744d9b | 116 | } |
38b19a92 RM |
117 | |
118 | return _URC_NO_REASON; | |
18744d9b BM |
119 | } |
120 | #endif |