Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6515 serge 1
/* DWARF2 EH unwinding support for FreeBSD: AMD x86-64 and x86.
2
   Copyright (C) 2015 Free Software Foundation, Inc.
3
   Contributed by John Marino 
4
 
5
This file is part of GCC.
6
 
7
GCC is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 3, or (at your option)
10
any later version.
11
 
12
GCC is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
GNU General Public License 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
/* Do code reading to identify a signal frame, and set the frame
27
   state data appropriately.  See unwind-dw2.c for the structs. */
28
 
29
#include 
30
#include 
31
#include 
32
#include 
33
 
34
#define REG_NAME(reg)	sf_uc.uc_mcontext.mc_## reg
35
 
36
#ifdef __x86_64__
37
#define MD_FALLBACK_FRAME_STATE_FOR x86_64_freebsd_fallback_frame_state
38
 
39
static _Unwind_Reason_Code
40
x86_64_freebsd_fallback_frame_state
41
(struct _Unwind_Context *context, _Unwind_FrameState *fs)
42
{
43
  struct sigframe *sf;
44
  long new_cfa;
45
 
46
  /* Prior to FreeBSD 9, the signal trampoline was located immediately
47
     before the ps_strings.  To support non-executable stacks on AMD64,
48
     the sigtramp was moved to a shared page for FreeBSD 9.  Unfortunately
49
     this means looking frame patterns again (sys/amd64/amd64/sigtramp.S)
50
     rather than using the robust and convenient KERN_PS_STRINGS trick.
51
 
52
     :  lea     0x10(%rsp),%rdi
53
     :  pushq   $0x0
54
     :  mov     $0x1a1,%rax
55
     :  syscall
56
 
57
     If we can't find this pattern, we're at the end of the stack.
58
  */
59
 
60
  if (!(   *(unsigned int *)(context->ra)      == 0x247c8d48
61
        && *(unsigned int *)(context->ra +  4) == 0x48006a10
62
        && *(unsigned int *)(context->ra +  8) == 0x01a1c0c7
63
        && *(unsigned int *)(context->ra + 12) == 0x050f0000 ))
64
    return _URC_END_OF_STACK;
65
 
66
  sf = (struct sigframe *) context->cfa;
67
  new_cfa = sf->REG_NAME(rsp);
68
  fs->regs.cfa_how = CFA_REG_OFFSET;
69
  /* Register 7 is rsp  */
70
  fs->regs.cfa_reg = 7;
71
  fs->regs.cfa_offset = new_cfa - (long) context->cfa;
72
 
73
  /* The SVR4 register numbering macros aren't usable in libgcc.  */
74
  fs->regs.reg[0].how = REG_SAVED_OFFSET;
75
  fs->regs.reg[0].loc.offset = (long)&sf->REG_NAME(rax) - new_cfa;
76
  fs->regs.reg[1].how = REG_SAVED_OFFSET;
77
  fs->regs.reg[1].loc.offset = (long)&sf->REG_NAME(rdx) - new_cfa;
78
  fs->regs.reg[2].how = REG_SAVED_OFFSET;
79
  fs->regs.reg[2].loc.offset = (long)&sf->REG_NAME(rcx) - new_cfa;
80
  fs->regs.reg[3].how = REG_SAVED_OFFSET;
81
  fs->regs.reg[3].loc.offset = (long)&sf->REG_NAME(rbx) - new_cfa;
82
  fs->regs.reg[4].how = REG_SAVED_OFFSET;
83
  fs->regs.reg[4].loc.offset = (long)&sf->REG_NAME(rsi) - new_cfa;
84
  fs->regs.reg[5].how = REG_SAVED_OFFSET;
85
  fs->regs.reg[5].loc.offset = (long)&sf->REG_NAME(rdi) - new_cfa;
86
  fs->regs.reg[6].how = REG_SAVED_OFFSET;
87
  fs->regs.reg[6].loc.offset = (long)&sf->REG_NAME(rbp) - new_cfa;
88
  fs->regs.reg[8].how = REG_SAVED_OFFSET;
89
  fs->regs.reg[8].loc.offset = (long)&sf->REG_NAME(r8) - new_cfa;
90
  fs->regs.reg[9].how = REG_SAVED_OFFSET;
91
  fs->regs.reg[9].loc.offset = (long)&sf->REG_NAME(r9) - new_cfa;
92
  fs->regs.reg[10].how = REG_SAVED_OFFSET;
93
  fs->regs.reg[10].loc.offset = (long)&sf->REG_NAME(r10) - new_cfa;
94
  fs->regs.reg[11].how = REG_SAVED_OFFSET;
95
  fs->regs.reg[11].loc.offset = (long)&sf->REG_NAME(r11) - new_cfa;
96
  fs->regs.reg[12].how = REG_SAVED_OFFSET;
97
  fs->regs.reg[12].loc.offset = (long)&sf->REG_NAME(r12) - new_cfa;
98
  fs->regs.reg[13].how = REG_SAVED_OFFSET;
99
  fs->regs.reg[13].loc.offset = (long)&sf->REG_NAME(r13) - new_cfa;
100
  fs->regs.reg[14].how = REG_SAVED_OFFSET;
101
  fs->regs.reg[14].loc.offset = (long)&sf->REG_NAME(r14) - new_cfa;
102
  fs->regs.reg[15].how = REG_SAVED_OFFSET;
103
  fs->regs.reg[15].loc.offset = (long)&sf->REG_NAME(r15) - new_cfa;
104
  fs->regs.reg[16].how = REG_SAVED_OFFSET;
105
  fs->regs.reg[16].loc.offset = (long)&sf->REG_NAME(rip) - new_cfa;
106
  fs->retaddr_column = 16;
107
  fs->signal_frame = 1;
108
  return _URC_NO_REASON;
109
}
110
 
111
#else /* Next section is for i386  */
112
 
113
#define MD_FALLBACK_FRAME_STATE_FOR x86_freebsd_fallback_frame_state
114
 
115
/*
116
 * We can't use KERN_PS_STRINGS anymore if we want to support FreeBSD32
117
 * compat on AMD64.  The sigtramp is in a shared page in that case so the
118
 * x86_sigtramp_range only works on a true i386 system.  We have to
119
 * search for the sigtramp frame if we want it working everywhere.
120
 */
121
 
122
static _Unwind_Reason_Code
123
x86_freebsd_fallback_frame_state
124
(struct _Unwind_Context *context, _Unwind_FrameState *fs)
125
{
126
  struct sigframe *sf;
127
  long new_cfa;
128
 
129
/*
130
 * i386 sigtramp frame we are looking for follows.
131
 * Apparently PSL_VM is variable, so we can't look past context->ra + 4
132
 * :
133
 *   0:	ff 54 24 10          	call   *0x10(%esp)          *SIGF_HANDLER
134
 *   4:	8d 44 24 20          	lea    0x20(%esp),%eax       SIGF_UC
135
 *   8:	50                   	push   %eax
136
 *   9:	f7 40 54 00 00 02 00 	testl  $0x20000,0x54(%eax)  $PSL_VM
137
 *  10:	75 03                	jne    15 
138
 *  12:	8e 68 14             	mov    0x14(%eax),%gs        UC_GS
139
 *  15:	b8 a1 01 00 00       	mov    0x1a1,%eax           $SYS_sigreturn
140
 */
141
 
142
  if (!(   *(unsigned int *)(context->ra - 4) == 0x102454ff
143
        && *(unsigned int *)(context->ra)     == 0x2024448d ))
144
    return _URC_END_OF_STACK;
145
 
146
  sf = (struct sigframe *) context->cfa;
147
  new_cfa = sf->REG_NAME(esp);
148
  fs->regs.cfa_how = CFA_REG_OFFSET;
149
  fs->regs.cfa_reg = 4;
150
  fs->regs.cfa_offset = new_cfa - (long) context->cfa;
151
 
152
  /* The SVR4 register numbering macros aren't usable in libgcc.  */
153
  fs->regs.reg[0].how = REG_SAVED_OFFSET;
154
  fs->regs.reg[0].loc.offset = (long)&sf->REG_NAME(eax) - new_cfa;
155
  fs->regs.reg[3].how = REG_SAVED_OFFSET;
156
  fs->regs.reg[3].loc.offset = (long)&sf->REG_NAME(ebx) - new_cfa;
157
  fs->regs.reg[1].how = REG_SAVED_OFFSET;
158
  fs->regs.reg[1].loc.offset = (long)&sf->REG_NAME(ecx) - new_cfa;
159
  fs->regs.reg[2].how = REG_SAVED_OFFSET;
160
  fs->regs.reg[2].loc.offset = (long)&sf->REG_NAME(edx) - new_cfa;
161
  fs->regs.reg[6].how = REG_SAVED_OFFSET;
162
  fs->regs.reg[6].loc.offset = (long)&sf->REG_NAME(esi) - new_cfa;
163
  fs->regs.reg[7].how = REG_SAVED_OFFSET;
164
  fs->regs.reg[7].loc.offset = (long)&sf->REG_NAME(edi) - new_cfa;
165
  fs->regs.reg[5].how = REG_SAVED_OFFSET;
166
  fs->regs.reg[5].loc.offset = (long)&sf->REG_NAME(ebp) - new_cfa;
167
  fs->regs.reg[8].how = REG_SAVED_OFFSET;
168
  fs->regs.reg[8].loc.offset = (long)&sf->REG_NAME(eip) - new_cfa;
169
  fs->retaddr_column = 8;
170
  fs->signal_frame = 1;
171
  return _URC_NO_REASON;
172
}
173
#endif /* ifdef __x86_64__  */