OSDN Git Service

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