Subversion Repositories Kolibri OS

Rev

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