]>
Commit | Line | Data |
---|---|---|
476d9098 | 1 | /* Darwin/powerpc host-specific hook definitions. |
ca2b05ba | 2 | Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
476d9098 | 3 | |
5de601cf NC |
4 | This file is part of GCC. |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU General Public License as published | |
8 | by the Free Software Foundation; either version 2, or (at your | |
9 | option) any later version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT | |
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
14 | License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GCC; see the file COPYING. If not, write to the | |
18 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, | |
19 | MA 02111-1307, USA. */ | |
476d9098 GK |
20 | |
21 | #include "config.h" | |
22 | #include "system.h" | |
23 | #include "coretypes.h" | |
24 | #include <signal.h> | |
25 | #include <sys/ucontext.h> | |
18c81520 | 26 | #include <sys/mman.h> |
476d9098 GK |
27 | #include "hosthooks.h" |
28 | #include "hosthooks-def.h" | |
29 | #include "toplev.h" | |
505b0fd6 | 30 | #include "diagnostic.h" |
476d9098 | 31 | |
5f5bfdd0 GK |
32 | static void segv_crash_handler (int); |
33 | static void segv_handler (int, siginfo_t *, void *); | |
34 | static void darwin_rs6000_extra_signals (void); | |
476d9098 | 35 | |
5f5bfdd0 GK |
36 | /* This doesn't have a prototype in signal.h in 10.2.x and earlier, |
37 | fixed in later releases. */ | |
38 | extern int sigaltstack(const struct sigaltstack *, struct sigaltstack *); | |
476d9098 GK |
39 | |
40 | #undef HOST_HOOKS_EXTRA_SIGNALS | |
41 | #define HOST_HOOKS_EXTRA_SIGNALS darwin_rs6000_extra_signals | |
42 | ||
a693fbb9 GK |
43 | /* On Darwin/powerpc, hitting the stack limit turns into a SIGSEGV. |
44 | This code detects the difference between hitting the stack limit and | |
45 | a true wild pointer dereference by looking at the instruction that | |
46 | faulted; only a few kinds of instruction are used to access below | |
47 | the previous bottom of the stack. */ | |
476d9098 GK |
48 | |
49 | static void | |
5f5bfdd0 | 50 | segv_crash_handler (int sig ATTRIBUTE_UNUSED) |
476d9098 GK |
51 | { |
52 | internal_error ("Segmentation Fault (code)"); | |
53 | } | |
54 | ||
55 | static void | |
5f5bfdd0 GK |
56 | segv_handler (int sig ATTRIBUTE_UNUSED, |
57 | siginfo_t *sip ATTRIBUTE_UNUSED, | |
58 | void *scp) | |
476d9098 GK |
59 | { |
60 | ucontext_t *uc = (ucontext_t *)scp; | |
61 | unsigned faulting_insn; | |
62 | ||
63 | /* The fault might have happened when trying to run some instruction, in | |
64 | which case the next line will segfault _again_. Handle this case. */ | |
65 | signal (SIGSEGV, segv_crash_handler); | |
66 | ||
67 | faulting_insn = *(unsigned *)uc->uc_mcontext->ss.srr0; | |
68 | ||
69 | /* Note that this only has to work for GCC, so we don't have to deal | |
70 | with all the possible cases (GCC has no AltiVec code, for | |
71 | instance). It's complicated because Darwin allows stores to | |
72 | below the stack pointer, and the prologue code takes advantage of | |
73 | this. */ | |
74 | ||
75 | if ((faulting_insn & 0xFFFF8000) == 0x94218000 /* stwu %r1, -xxx(%r1) */ | |
76 | || (faulting_insn & 0xFFFF03FF) == 0x7C21016E /* stwux %r1, xxx, %r1 */ | |
77 | || (faulting_insn & 0xFC1F8000) == 0x90018000 /* stw xxx, -yyy(%r1) */ | |
78 | || (faulting_insn & 0xFC1F8000) == 0xD8018000 /* stfd xxx, -yyy(%r1) */ | |
79 | || (faulting_insn & 0xFC1F8000) == 0xBC018000 /* stmw xxx, -yyy(%r1) */) | |
80 | { | |
81 | char *shell_name; | |
82 | ||
83 | fnotice (stderr, "Out of stack space.\n"); | |
84 | shell_name = getenv ("SHELL"); | |
85 | if (shell_name != NULL) | |
86 | shell_name = strrchr (shell_name, '/'); | |
87 | if (shell_name != NULL) | |
88 | { | |
89 | static const char * shell_commands[][2] = { | |
90 | { "sh", "ulimit -S -s unlimited" }, | |
91 | { "bash", "ulimit -S -s unlimited" }, | |
92 | { "tcsh", "limit stacksize unlimited" }, | |
93 | { "csh", "limit stacksize unlimited" }, | |
94 | /* zsh doesn't have "unlimited", this will work under the | |
95 | default configuration. */ | |
96 | { "zsh", "limit stacksize 32m" } | |
97 | }; | |
98 | size_t i; | |
99 | ||
100 | for (i = 0; i < ARRAY_SIZE (shell_commands); i++) | |
101 | if (strcmp (shell_commands[i][0], shell_name + 1) == 0) | |
102 | { | |
103 | fnotice (stderr, | |
104 | "Try running `%s' in the shell to raise its limit.\n", | |
105 | shell_commands[i][1]); | |
106 | } | |
107 | } | |
108 | ||
505b0fd6 GK |
109 | if (global_dc->abort_on_error) |
110 | abort (); | |
111 | ||
476d9098 GK |
112 | exit (FATAL_EXIT_CODE); |
113 | } | |
114 | ||
115 | fprintf (stderr, "[address=%08lx pc=%08x]\n", | |
116 | uc->uc_mcontext->es.dar, uc->uc_mcontext->ss.srr0); | |
117 | internal_error ("Segmentation Fault"); | |
118 | exit (FATAL_EXIT_CODE); | |
119 | } | |
120 | ||
121 | static void | |
5f5bfdd0 | 122 | darwin_rs6000_extra_signals (void) |
476d9098 GK |
123 | { |
124 | struct sigaction sact; | |
125 | stack_t sigstk; | |
126 | ||
127 | sigstk.ss_sp = xmalloc (SIGSTKSZ); | |
128 | sigstk.ss_size = SIGSTKSZ; | |
129 | sigstk.ss_flags = 0; | |
130 | if (sigaltstack (&sigstk, NULL) < 0) | |
fa6ef813 | 131 | fatal_error ("While setting up signal stack: %m"); |
476d9098 GK |
132 | |
133 | sigemptyset(&sact.sa_mask); | |
134 | sact.sa_flags = SA_ONSTACK | SA_SIGINFO; | |
135 | sact.sa_sigaction = segv_handler; | |
136 | if (sigaction (SIGSEGV, &sact, 0) < 0) | |
fa6ef813 | 137 | fatal_error ("While setting up signal handler: %m"); |
476d9098 | 138 | } |
18c81520 | 139 | \f |
18c81520 GK |
140 | #undef HOST_HOOKS_GT_PCH_GET_ADDRESS |
141 | #define HOST_HOOKS_GT_PCH_GET_ADDRESS darwin_rs6000_gt_pch_get_address | |
142 | #undef HOST_HOOKS_GT_PCH_USE_ADDRESS | |
143 | #define HOST_HOOKS_GT_PCH_USE_ADDRESS darwin_rs6000_gt_pch_use_address | |
144 | ||
18c81520 GK |
145 | /* Yes, this is really supposed to work. */ |
146 | static char pch_address_space[1024*1024*1024] __attribute__((aligned (4096))); | |
147 | ||
148 | /* Return the address of the PCH address space, if the PCH will fit in it. */ | |
149 | ||
150 | static void * | |
4d0c31e6 | 151 | darwin_rs6000_gt_pch_get_address (size_t sz, int fd ATTRIBUTE_UNUSED) |
18c81520 GK |
152 | { |
153 | if (sz <= sizeof (pch_address_space)) | |
154 | return pch_address_space; | |
155 | else | |
156 | return NULL; | |
157 | } | |
158 | ||
159 | /* Check ADDR and SZ for validity, and deallocate (using munmap) that part of | |
160 | pch_address_space beyond SZ. */ | |
161 | ||
4d0c31e6 RH |
162 | static int |
163 | darwin_rs6000_gt_pch_use_address (void *addr, size_t sz, int fd, size_t off) | |
18c81520 GK |
164 | { |
165 | const size_t pagesize = getpagesize(); | |
4d0c31e6 RH |
166 | void *mmap_result; |
167 | int ret; | |
18c81520 GK |
168 | |
169 | if ((size_t)pch_address_space % pagesize != 0 | |
170 | || sizeof (pch_address_space) % pagesize != 0) | |
171 | abort (); | |
172 | ||
4319ac92 AP |
173 | ret = (addr == pch_address_space && sz <= sizeof (pch_address_space)); |
174 | if (! ret) | |
18c81520 GK |
175 | sz = 0; |
176 | ||
177 | /* Round the size to a whole page size. Normally this is a no-op. */ | |
178 | sz = (sz + pagesize - 1) / pagesize * pagesize; | |
179 | ||
180 | if (munmap (pch_address_space + sz, sizeof (pch_address_space) - sz) != 0) | |
181 | fatal_error ("couldn't unmap pch_address_space: %m\n"); | |
182 | ||
4e4083ad ILT |
183 | if (ret) |
184 | { | |
185 | mmap_result = mmap (addr, sz, | |
186 | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, | |
187 | fd, off); | |
4d0c31e6 | 188 | |
4e4083ad | 189 | /* The file might not be mmap-able. */ |
febc5365 | 190 | ret = mmap_result != (void *) MAP_FAILED; |
4d0c31e6 | 191 | |
4e4083ad | 192 | /* Sanity check for broken MAP_FIXED. */ |
febc5365 | 193 | if (ret && mmap_result != addr) |
4e4083ad ILT |
194 | abort (); |
195 | } | |
4d0c31e6 RH |
196 | |
197 | return ret; | |
18c81520 | 198 | } |
4d0c31e6 | 199 | \f |
476d9098 GK |
200 | |
201 | const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; |