Subversion Repositories Kolibri OS

Rev

Rev 4383 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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