w32-unwind.h revision 1.1.1.1.4.2 1 1.1.1.1.4.2 yamt /* Definitions for Dwarf2 EH unwind support for Windows32 targets
2 1.1.1.1.4.2 yamt Copyright (C) 2007-2013 Free Software Foundation, Inc.
3 1.1.1.1.4.2 yamt Contributed by Pascal Obry <obry (at) adacore.com>
4 1.1.1.1.4.2 yamt
5 1.1.1.1.4.2 yamt This file is part of GCC.
6 1.1.1.1.4.2 yamt
7 1.1.1.1.4.2 yamt GCC is free software; you can redistribute it and/or modify it under
8 1.1.1.1.4.2 yamt the terms of the GNU General Public License as published by the Free
9 1.1.1.1.4.2 yamt Software Foundation; either version 3, or (at your option) any later
10 1.1.1.1.4.2 yamt version.
11 1.1.1.1.4.2 yamt
12 1.1.1.1.4.2 yamt GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 1.1.1.1.4.2 yamt WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 1.1.1.1.4.2 yamt FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 1.1.1.1.4.2 yamt for more details.
16 1.1.1.1.4.2 yamt
17 1.1.1.1.4.2 yamt Under Section 7 of GPL version 3, you are granted additional
18 1.1.1.1.4.2 yamt permissions described in the GCC Runtime Library Exception, version
19 1.1.1.1.4.2 yamt 3.1, as published by the Free Software Foundation.
20 1.1.1.1.4.2 yamt
21 1.1.1.1.4.2 yamt You should have received a copy of the GNU General Public License and
22 1.1.1.1.4.2 yamt a copy of the GCC Runtime Library Exception along with this program;
23 1.1.1.1.4.2 yamt see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 1.1.1.1.4.2 yamt <http://www.gnu.org/licenses/>. */
25 1.1.1.1.4.2 yamt
26 1.1.1.1.4.2 yamt
27 1.1.1.1.4.2 yamt /* This file implements the md_fallback_frame_state_for routine for
28 1.1.1.1.4.2 yamt Windows, triggered when the GCC table based unwinding process hits a
29 1.1.1.1.4.2 yamt frame for which no unwind info has been registered. This typically
30 1.1.1.1.4.2 yamt occurs when raising an exception from a signal handler, because the
31 1.1.1.1.4.2 yamt handler is actually called from the OS kernel.
32 1.1.1.1.4.2 yamt
33 1.1.1.1.4.2 yamt The basic idea is to detect that we are indeed trying to unwind past a
34 1.1.1.1.4.2 yamt signal handler and to fill out the GCC internal unwinding structures for
35 1.1.1.1.4.2 yamt the OS kernel frame as if it had been directly called from the
36 1.1.1.1.4.2 yamt interrupted context.
37 1.1.1.1.4.2 yamt
38 1.1.1.1.4.2 yamt This is all assuming that the code to set the handler asked the kernel
39 1.1.1.1.4.2 yamt to pass a pointer to such context information.
40 1.1.1.1.4.2 yamt
41 1.1.1.1.4.2 yamt There is three main parts.
42 1.1.1.1.4.2 yamt
43 1.1.1.1.4.2 yamt 1) The first thing to do is to check if we are in a signal context. If
44 1.1.1.1.4.2 yamt not we can just return as there is nothing to do. We are probably on
45 1.1.1.1.4.2 yamt some foreign code for which no unwind frame can be found. If this is
46 1.1.1.1.4.2 yamt a call from the Windows signal handler, then:
47 1.1.1.1.4.2 yamt
48 1.1.1.1.4.2 yamt 2) We must get the signal context information.
49 1.1.1.1.4.2 yamt
50 1.1.1.1.4.2 yamt * With the standard exception filter:
51 1.1.1.1.4.2 yamt
52 1.1.1.1.4.2 yamt This is on Windows pointed to by an EXCEPTION_POINTERS. We know that
53 1.1.1.1.4.2 yamt the signal handle will call an UnhandledExceptionFilter with this
54 1.1.1.1.4.2 yamt parameter. The spec for this routine is:
55 1.1.1.1.4.2 yamt
56 1.1.1.1.4.2 yamt LONG WINAPI UnhandledExceptionFilter(struct _EXCEPTION_POINTERS*);
57 1.1.1.1.4.2 yamt
58 1.1.1.1.4.2 yamt So the pointer to struct _EXCEPTION_POINTERS must be somewhere on the
59 1.1.1.1.4.2 yamt stack.
60 1.1.1.1.4.2 yamt
61 1.1.1.1.4.2 yamt This was found experimentally to always be at offset 0 of the context
62 1.1.1.1.4.2 yamt frame in all cases handled by this implementation.
63 1.1.1.1.4.2 yamt
64 1.1.1.1.4.2 yamt * With the SEH exception handler:
65 1.1.1.1.4.2 yamt
66 1.1.1.1.4.2 yamt In this case the signal context is directly on the stack as the SEH
67 1.1.1.1.4.2 yamt exception handler has the following prototype:
68 1.1.1.1.4.2 yamt
69 1.1.1.1.4.2 yamt DWORD
70 1.1.1.1.4.2 yamt SEH_error_handler (PEXCEPTION_RECORD ExceptionRecord,
71 1.1.1.1.4.2 yamt PVOID EstablisherFrame,
72 1.1.1.1.4.2 yamt PCONTEXT ContextRecord,
73 1.1.1.1.4.2 yamt PVOID DispatcherContext)
74 1.1.1.1.4.2 yamt
75 1.1.1.1.4.2 yamt This was found experimentally to always be at offset 56 of the
76 1.1.1.1.4.2 yamt context frame in all cases handled by this implementation.
77 1.1.1.1.4.2 yamt
78 1.1.1.1.4.2 yamt 3) When we have the signal context we just have to save some registers
79 1.1.1.1.4.2 yamt and set the return address based on the program counter (Eip).
80 1.1.1.1.4.2 yamt
81 1.1.1.1.4.2 yamt Note that this implementation follows closely the same principles as the
82 1.1.1.1.4.2 yamt GNU/Linux and OSF ones. */
83 1.1.1.1.4.2 yamt
84 1.1.1.1.4.2 yamt #ifndef __MINGW64__
85 1.1.1.1.4.2 yamt
86 1.1.1.1.4.2 yamt #define WIN32_MEAN_AND_LEAN
87 1.1.1.1.4.2 yamt #include <windows.h>
88 1.1.1.1.4.2 yamt /* Patterns found experimentally to be on a Windows signal handler */
89 1.1.1.1.4.2 yamt
90 1.1.1.1.4.2 yamt /* In a standard exception filter */
91 1.1.1.1.4.2 yamt
92 1.1.1.1.4.2 yamt #define SIG_PAT1 \
93 1.1.1.1.4.2 yamt (pc_[-2] == 0xff && pc_[-1] == 0xd0 /* call %eax */ \
94 1.1.1.1.4.2 yamt && pc_[0] == 0x83 && pc_[1] == 0xf8) /* cmp 0xdepl,%eax */
95 1.1.1.1.4.2 yamt
96 1.1.1.1.4.2 yamt #define SIG_PAT2 \
97 1.1.1.1.4.2 yamt (pc_[-5] == 0xe8 && pc_[-4] == 0x68 /* call (depl16) */ \
98 1.1.1.1.4.2 yamt && pc_[0] == 0xc3) /* ret */
99 1.1.1.1.4.2 yamt
100 1.1.1.1.4.2 yamt /* In a Win32 SEH handler */
101 1.1.1.1.4.2 yamt
102 1.1.1.1.4.2 yamt #define SIG_SEH1 \
103 1.1.1.1.4.2 yamt (pc_[-5] == 0xe8 /* call addr */ \
104 1.1.1.1.4.2 yamt && pc_[0] == 0x83 && pc_[1] == 0xc4 /* add 0xval,%esp */ \
105 1.1.1.1.4.2 yamt && pc_[3] == 0xb8) /* mov 0xval,%eax */
106 1.1.1.1.4.2 yamt
107 1.1.1.1.4.2 yamt #define SIG_SEH2 \
108 1.1.1.1.4.2 yamt (pc_[-5] == 0x8b && pc_[-4] == 0x4d /* mov depl(%ebp),%ecx */ \
109 1.1.1.1.4.2 yamt && pc_[0] == 0x64 && pc_[1] == 0x8b) /* mov %fs:(0),<reg> */ \
110 1.1.1.1.4.2 yamt
111 1.1.1.1.4.2 yamt /* In the GCC alloca (stack probing) */
112 1.1.1.1.4.2 yamt
113 1.1.1.1.4.2 yamt #define SIG_ALLOCA \
114 1.1.1.1.4.2 yamt (pc_[-1] == 0x83 /* orl $0x0,(%ecx) */ \
115 1.1.1.1.4.2 yamt && pc_[0] == 0x9 && pc_[1] == 0 \
116 1.1.1.1.4.2 yamt && pc_[2] == 0x2d && pc_[3] == 0 /* subl $0x1000,%eax */ \
117 1.1.1.1.4.2 yamt && pc_[4] == 0x10 && pc_[5] == 0)
118 1.1.1.1.4.2 yamt
119 1.1.1.1.4.2 yamt
120 1.1.1.1.4.2 yamt #define MD_FALLBACK_FRAME_STATE_FOR i386_w32_fallback_frame_state
121 1.1.1.1.4.2 yamt
122 1.1.1.1.4.2 yamt static _Unwind_Reason_Code
123 1.1.1.1.4.2 yamt i386_w32_fallback_frame_state (struct _Unwind_Context *context,
124 1.1.1.1.4.2 yamt _Unwind_FrameState *fs)
125 1.1.1.1.4.2 yamt
126 1.1.1.1.4.2 yamt {
127 1.1.1.1.4.2 yamt void * ctx_ra_ = (void *)(context->ra); /* return address */
128 1.1.1.1.4.2 yamt void * ctx_cfa_ = (void *)(context->cfa); /* context frame address */
129 1.1.1.1.4.2 yamt unsigned char * pc_ = (unsigned char *) ctx_ra_;
130 1.1.1.1.4.2 yamt
131 1.1.1.1.4.2 yamt /* In the test below we look for two specific patterns found
132 1.1.1.1.4.2 yamt experimentally to be in the Windows signal handler. */
133 1.1.1.1.4.2 yamt if (SIG_PAT1 || SIG_PAT2 || SIG_SEH1 || SIG_SEH2)
134 1.1.1.1.4.2 yamt {
135 1.1.1.1.4.2 yamt PEXCEPTION_POINTERS weinfo_;
136 1.1.1.1.4.2 yamt PCONTEXT proc_ctx_;
137 1.1.1.1.4.2 yamt long new_cfa_;
138 1.1.1.1.4.2 yamt
139 1.1.1.1.4.2 yamt if (SIG_SEH1)
140 1.1.1.1.4.2 yamt proc_ctx_ = (PCONTEXT) (*(int*)(ctx_cfa_ + 56));
141 1.1.1.1.4.2 yamt else if (SIG_SEH2)
142 1.1.1.1.4.2 yamt proc_ctx_ = (PCONTEXT) (*(int*)(ctx_cfa_ + 8));
143 1.1.1.1.4.2 yamt else
144 1.1.1.1.4.2 yamt {
145 1.1.1.1.4.2 yamt weinfo_ = (PEXCEPTION_POINTERS) (*(int*)ctx_cfa_);
146 1.1.1.1.4.2 yamt proc_ctx_ = weinfo_->ContextRecord;
147 1.1.1.1.4.2 yamt }
148 1.1.1.1.4.2 yamt
149 1.1.1.1.4.2 yamt /* The new context frame address is the stack pointer. */
150 1.1.1.1.4.2 yamt new_cfa_ = proc_ctx_->Esp;
151 1.1.1.1.4.2 yamt fs->regs.cfa_how = CFA_REG_OFFSET;
152 1.1.1.1.4.2 yamt fs->regs.cfa_reg = __builtin_dwarf_sp_column();
153 1.1.1.1.4.2 yamt fs->regs.cfa_offset = new_cfa_ - (long) ctx_cfa_;
154 1.1.1.1.4.2 yamt
155 1.1.1.1.4.2 yamt /* Restore registers. */
156 1.1.1.1.4.2 yamt fs->regs.reg[0].how = REG_SAVED_OFFSET;
157 1.1.1.1.4.2 yamt fs->regs.reg[0].loc.offset = (long)&proc_ctx_->Eax - new_cfa_;
158 1.1.1.1.4.2 yamt fs->regs.reg[3].how = REG_SAVED_OFFSET;
159 1.1.1.1.4.2 yamt fs->regs.reg[3].loc.offset = (long)&proc_ctx_->Ebx - new_cfa_;
160 1.1.1.1.4.2 yamt fs->regs.reg[1].how = REG_SAVED_OFFSET;
161 1.1.1.1.4.2 yamt fs->regs.reg[1].loc.offset = (long)&proc_ctx_->Ecx - new_cfa_;
162 1.1.1.1.4.2 yamt fs->regs.reg[2].how = REG_SAVED_OFFSET;
163 1.1.1.1.4.2 yamt fs->regs.reg[2].loc.offset = (long)&proc_ctx_->Edx - new_cfa_;
164 1.1.1.1.4.2 yamt fs->regs.reg[6].how = REG_SAVED_OFFSET;
165 1.1.1.1.4.2 yamt fs->regs.reg[6].loc.offset = (long)&proc_ctx_->Esi - new_cfa_;
166 1.1.1.1.4.2 yamt fs->regs.reg[7].how = REG_SAVED_OFFSET;
167 1.1.1.1.4.2 yamt fs->regs.reg[7].loc.offset = (long)&proc_ctx_->Edi - new_cfa_;
168 1.1.1.1.4.2 yamt fs->regs.reg[5].how = REG_SAVED_OFFSET;
169 1.1.1.1.4.2 yamt fs->regs.reg[5].loc.offset = (long)&proc_ctx_->Ebp - new_cfa_;
170 1.1.1.1.4.2 yamt fs->regs.reg[8].how = REG_SAVED_OFFSET;
171 1.1.1.1.4.2 yamt fs->regs.reg[8].loc.offset = (long)&proc_ctx_->Eip - new_cfa_;
172 1.1.1.1.4.2 yamt fs->retaddr_column = 8;
173 1.1.1.1.4.2 yamt fs->signal_frame = 1;
174 1.1.1.1.4.2 yamt
175 1.1.1.1.4.2 yamt return _URC_NO_REASON;
176 1.1.1.1.4.2 yamt }
177 1.1.1.1.4.2 yamt
178 1.1.1.1.4.2 yamt /* Unwinding through _alloca, propagating from a trap triggered by
179 1.1.1.1.4.2 yamt one of it's probes prior to the real SP adjustment. The only
180 1.1.1.1.4.2 yamt operations of interest performed is "pushl %ecx", followed by
181 1.1.1.1.4.2 yamt ecx clobbering. */
182 1.1.1.1.4.2 yamt else if (SIG_ALLOCA)
183 1.1.1.1.4.2 yamt {
184 1.1.1.1.4.2 yamt /* Only one push between entry in _alloca and the probe trap. */
185 1.1.1.1.4.2 yamt long new_cfa_ = (long) ctx_cfa_ + 4;
186 1.1.1.1.4.2 yamt
187 1.1.1.1.4.2 yamt fs->regs.cfa_how = CFA_REG_OFFSET;
188 1.1.1.1.4.2 yamt fs->regs.cfa_reg = __builtin_dwarf_sp_column();
189 1.1.1.1.4.2 yamt fs->regs.cfa_offset = new_cfa_ - (long) ctx_cfa_;
190 1.1.1.1.4.2 yamt
191 1.1.1.1.4.2 yamt /* The saved value of %ecx is at CFA - 4 */
192 1.1.1.1.4.2 yamt fs->regs.reg[1].how = REG_SAVED_OFFSET;
193 1.1.1.1.4.2 yamt fs->regs.reg[1].loc.offset = -4;
194 1.1.1.1.4.2 yamt
195 1.1.1.1.4.2 yamt /* and what is stored at the CFA is the return address. */
196 1.1.1.1.4.2 yamt fs->retaddr_column = 8;
197 1.1.1.1.4.2 yamt fs->regs.reg[8].how = REG_SAVED_OFFSET;
198 1.1.1.1.4.2 yamt fs->regs.reg[8].loc.offset = 0;
199 1.1.1.1.4.2 yamt fs->signal_frame = 1;
200 1.1.1.1.4.2 yamt
201 1.1.1.1.4.2 yamt return _URC_NO_REASON;
202 1.1.1.1.4.2 yamt }
203 1.1.1.1.4.2 yamt else
204 1.1.1.1.4.2 yamt return _URC_END_OF_STACK;
205 1.1.1.1.4.2 yamt }
206 1.1.1.1.4.2 yamt
207 1.1.1.1.4.2 yamt #endif /* !__MINGW64__ */
208