2 |
|
* paranoia.cpp - Check undocumented features of the Linux kernel that |
3 |
|
* SheepShaver relies upon |
4 |
|
* |
5 |
< |
* SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig |
5 |
> |
* SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig |
6 |
|
* |
7 |
|
* This program is free software; you can redistribute it and/or modify |
8 |
|
* it under the terms of the GNU General Public License as published by |
42 |
|
|
43 |
|
// Prototypes |
44 |
|
extern "C" void *get_sp(void); |
45 |
< |
extern "C" void set_r2(uint32 val); |
45 |
> |
extern "C" void *get_r2(void); |
46 |
> |
extern "C" void set_r2(void *); |
47 |
> |
extern "C" void *get_r13(void); |
48 |
|
extern void paranoia_check(void); |
49 |
|
static void sigusr2_handler(int sig, sigcontext_struct *sc); |
50 |
|
|
59 |
|
static uint32 sig_r2 = 0; |
60 |
|
|
61 |
|
|
62 |
+ |
int raise(int sig) |
63 |
+ |
{ |
64 |
+ |
// Reimplement to get rid of access to r2 (TLS pointer) |
65 |
+ |
return kill(getpid(), sig); |
66 |
+ |
} |
67 |
+ |
|
68 |
|
void paranoia_check(void) |
69 |
|
{ |
70 |
|
char str[256]; |
103 |
|
} |
104 |
|
|
105 |
|
// Raise SIGUSR2 |
106 |
< |
set_r2(0xaffebad5); |
106 |
> |
TOC = get_r2(); |
107 |
> |
R13 = get_r13(); |
108 |
> |
set_r2((void *)0xaffebad5); |
109 |
|
raise(SIGUSR2); |
110 |
+ |
if (TOC != get_r2()) |
111 |
+ |
err = 6; |
112 |
+ |
if (R13 != get_r13()) |
113 |
+ |
err = 7; |
114 |
|
|
115 |
|
// Check error code |
116 |
|
switch (err) { |
129 |
|
case 5: |
130 |
|
printf("FATAL: sc->regs->gpr[2] in signal handler (%08lx) doesn't have expected value (%08x)\n", (uint32)sig_r2, 0xaffebad5); |
131 |
|
break; |
132 |
+ |
case 6: |
133 |
+ |
printf("FATAL: signal handler failed to restore initial r2 value (%08x, was %08x)\n", (uint32)get_r2(), (uint32)TOC); |
134 |
+ |
break; |
135 |
+ |
case 7: |
136 |
+ |
printf("FATAL: signal handler failed to restore initial r13 value (%08x, was %08x)\n", get_r13(), (uint32)R13); |
137 |
|
} |
138 |
|
if (err) { |
139 |
|
printf("Maybe you need a different kernel?\n"); |
154 |
|
sig_sp = get_sp(); |
155 |
|
if (sig_sp < sig_stack || sig_sp >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { |
156 |
|
err = 1; |
157 |
< |
return; |
157 |
> |
goto ret; |
158 |
|
} |
159 |
|
|
160 |
|
// Check whether r4 points to info on the stack |
161 |
|
sig_r4 = sc; |
162 |
|
if (sig_r4 < sig_stack || sig_r4 >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { |
163 |
|
err = 2; |
164 |
< |
return; |
164 |
> |
goto ret; |
165 |
|
} |
166 |
|
|
167 |
|
// Check whether r4 looks like a sigcontext |
168 |
|
sig_sc_signal = sc->signal; |
169 |
|
if (sig_sc_signal != SIGUSR2) { |
170 |
|
err = 3; |
171 |
< |
return; |
171 |
> |
goto ret; |
172 |
|
} |
173 |
|
|
174 |
|
// Check whether sc->regs points to info on the stack |
175 |
|
sig_sc_regs = sc->regs; |
176 |
|
if (sig_sc_regs < sig_stack || sig_sc_regs >= ((uint8 *)sig_stack + SIG_STACK_SIZE)) { |
177 |
|
err = 4; |
178 |
< |
return; |
178 |
> |
goto ret; |
179 |
|
} |
180 |
|
|
181 |
|
// Check whether r2 still holds the value we set it to |
182 |
|
sig_r2 = sc->regs->gpr[2]; |
183 |
|
if (sig_r2 != 0xaffebad5) { |
184 |
|
err = 5; |
185 |
< |
return; |
185 |
> |
goto ret; |
186 |
|
} |
187 |
+ |
|
188 |
+ |
// Restore pointer to Thread Local Storage |
189 |
+ |
ret: |
190 |
+ |
#ifdef SYSTEM_CLOBBERS_R2 |
191 |
+ |
sc->regs->gpr[2] = (unsigned long)TOC; |
192 |
+ |
#endif |
193 |
|
} |