]>
Commit | Line | Data |
---|---|---|
0f840cc8 | 1 | 1999-07-29 Jim Blandy <jimb@savonarola.red-bean.com> |
2 | ||
3 | Change from Ian Lance Taylor <ian@zembu.com>. The | |
4 | i386_linux_sigtramp* functions should be moved to | |
5 | i386-linux-tdep.c, when that file is introduced. | |
6 | ||
7 | * config/i386/tm-linux.h (LINUX_SIGCONTEXT_SIZE): Define. | |
8 | (LINUX_SIGCONTEXT_PC_OFFSET): Define. | |
9 | (LINUX_SIGCONTEXT_SP_OFFSET): Define. | |
10 | (SIGCONTEXT_PC_OFFSET): Don't define. | |
11 | (I386_LINUX_SIGTRAMP): Define. | |
12 | (IN_SIGTRAMP): Define. | |
13 | (i386_linux_sigtramp): Declare. | |
14 | (sigtramp_saved_pc): Define. | |
15 | (i386_linux_sigtramp_saved_pc): Declare. | |
16 | (FRAMELESS_SIGNAL): Define. | |
17 | (FRAME_CHAIN, FRAME_SAVED_PC): Define after #undef. | |
18 | * i386-tdep.c (i386_linux_sigtramp_start): New static function if | |
19 | I386_LINUX_SIGTRAMP. | |
20 | (i386_linux_sigtramp): New function if I386_LINUX_SIGTRAMP. | |
21 | (i386_linux_sigtramp_saved_pc): Likewise. | |
22 | (i386_linux_sigtramp_saved_sp): Likewise. | |
23 | ||
24 | =================================================================== | |
25 | RCS file: /cvs/gdb/gdb/gdb/config/i386/tm-linux.h,v | |
26 | retrieving revision 1.1.1.2 | |
27 | retrieving revision 1.1.1.3 | |
28 | diff -c -r1.1.1.2 -r1.1.1.3 | |
29 | *** gdb-4.18/gdb/config/i386/tm-linux.h 1999/07/07 20:13:20 1.1.1.2 | |
30 | --- gdb-4.18/gdb/config/i386/tm-linux.h 1999/08/02 23:46:27 1.1.1.3 | |
31 | *************** | |
32 | *** 26,39 **** | |
33 | ||
34 | #include "i386/tm-i386.h" | |
35 | ||
36 | ! /* Offset to saved PC in sigcontext, from <linux/signal.h>. */ | |
37 | ! #define SIGCONTEXT_PC_OFFSET 38 | |
38 | ||
39 | /* We need this file for the SOLIB_TRAMPOLINE stuff. */ | |
40 | ||
41 | #include "tm-sysv4.h" | |
42 | ||
43 | /* The following works around a problem with /usr/include/sys/procfs.h */ | |
44 | #define sys_quotactl 1 | |
45 | ||
46 | #endif /* #ifndef TM_LINUX_H */ | |
47 | --- 26,107 ---- | |
48 | ||
49 | #include "i386/tm-i386.h" | |
50 | ||
51 | ! /* Size of sigcontext, from <asm/sigcontext.h>. */ | |
52 | ! #define LINUX_SIGCONTEXT_SIZE (88) | |
53 | ||
54 | + /* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */ | |
55 | + #define LINUX_SIGCONTEXT_PC_OFFSET (56) | |
56 | + | |
57 | + /* Offset to saved SP in sigcontext, from <asm/sigcontext.h>. */ | |
58 | + #define LINUX_SIGCONTEXT_SP_OFFSET (28) | |
59 | + | |
60 | /* We need this file for the SOLIB_TRAMPOLINE stuff. */ | |
61 | ||
62 | #include "tm-sysv4.h" | |
63 | ||
64 | /* The following works around a problem with /usr/include/sys/procfs.h */ | |
65 | #define sys_quotactl 1 | |
66 | + | |
67 | + /* When the i386 Linux kernel calls a signal handler, the return | |
68 | + address points to a bit of code on the stack. These definitions | |
69 | + are used to identify this bit of code as a signal trampoline in | |
70 | + order to support backtracing through calls to signal handlers. */ | |
71 | + | |
72 | + #define I386_LINUX_SIGTRAMP | |
73 | + #define IN_SIGTRAMP(pc, name) ((name) == NULL && i386_linux_sigtramp (pc)) | |
74 | + | |
75 | + extern int i386_linux_sigtramp PARAMS ((CORE_ADDR)); | |
76 | + | |
77 | + /* We need our own version of sigtramp_saved_pc to get the saved PC in | |
78 | + a sigtramp routine. */ | |
79 | + | |
80 | + #define sigtramp_saved_pc i386_linux_sigtramp_saved_pc | |
81 | + extern CORE_ADDR i386_linux_sigtramp_saved_pc PARAMS ((struct frame_info *)); | |
82 | + | |
83 | + /* Signal trampolines don't have a meaningful frame. As in tm-i386.h, | |
84 | + the frame pointer value we use is actually the frame pointer of the | |
85 | + calling frame--that is, the frame which was in progress when the | |
86 | + signal trampoline was entered. gdb mostly treats this frame | |
87 | + pointer value as a magic cookie. We detect the case of a signal | |
88 | + trampoline by looking at the SIGNAL_HANDLER_CALLER field, which is | |
89 | + set based on IN_SIGTRAMP. | |
90 | + | |
91 | + When a signal trampoline is invoked from a frameless function, we | |
92 | + essentially have two frameless functions in a row. In this case, | |
93 | + we use the same magic cookie for three frames in a row. We detect | |
94 | + this case by seeing whether the next frame has | |
95 | + SIGNAL_HANDLER_CALLER set, and, if it does, checking whether the | |
96 | + current frame is actually frameless. In this case, we need to get | |
97 | + the PC by looking at the SP register value stored in the signal | |
98 | + context. | |
99 | + | |
100 | + This should work in most cases except in horrible situations where | |
101 | + a signal occurs just as we enter a function but before the frame | |
102 | + has been set up. */ | |
103 | + | |
104 | + #define FRAMELESS_SIGNAL(FRAME) \ | |
105 | + ((FRAME)->next != NULL \ | |
106 | + && (FRAME)->next->signal_handler_caller \ | |
107 | + && frameless_look_for_prologue (FRAME)) | |
108 | + | |
109 | + #undef FRAME_CHAIN | |
110 | + #define FRAME_CHAIN(FRAME) \ | |
111 | + ((FRAME)->signal_handler_caller \ | |
112 | + ? (FRAME)->frame \ | |
113 | + : (FRAMELESS_SIGNAL (FRAME) \ | |
114 | + ? (FRAME)->frame \ | |
115 | + : (!inside_entry_file ((FRAME)->pc) \ | |
116 | + ? read_memory_integer ((FRAME)->frame, 4) \ | |
117 | + : 0))) | |
118 | + | |
119 | + #undef FRAME_SAVED_PC | |
120 | + #define FRAME_SAVED_PC(FRAME) \ | |
121 | + ((FRAME)->signal_handler_caller \ | |
122 | + ? sigtramp_saved_pc (FRAME) \ | |
123 | + : (FRAMELESS_SIGNAL (FRAME) \ | |
124 | + ? read_memory_integer (i386_linux_sigtramp_saved_sp ((FRAME)->next), 4) \ | |
125 | + : read_memory_integer ((FRAME)->frame + 4, 4))) | |
126 | + | |
127 | + extern CORE_ADDR i386_linux_sigtramp_saved_sp PARAMS ((struct frame_info *)); | |
128 | ||
129 | #endif /* #ifndef TM_LINUX_H */ | |
130 | Index: i386-tdep.c | |
131 | =================================================================== | |
132 | RCS file: /cvs/gdb/gdb/gdb/i386-tdep.c,v | |
133 | retrieving revision 1.1.1.4 | |
134 | retrieving revision 1.1.1.5 | |
135 | diff -c -r1.1.1.4 -r1.1.1.5 | |
136 | *** gdb-4.18/gdb/i386-tdep.c 1999/07/07 20:06:55 1.1.1.4 | |
137 | --- gdb-4.18/gdb/i386-tdep.c 1999/08/02 23:45:36 1.1.1.5 | |
138 | *************** | |
139 | *** 722,727 **** | |
140 | --- 722,861 ---- | |
141 | } | |
142 | #endif /* I386V4_SIGTRAMP_SAVED_PC */ | |
143 | ||
144 | + #ifdef I386_LINUX_SIGTRAMP | |
145 | + | |
146 | + /* When the i386 Linux kernel calls a signal handler, the return | |
147 | + address points to a bit of code on the stack. This function | |
148 | + returns whether the PC appears to be within this bit of code. | |
149 | + | |
150 | + The instruction sequence is | |
151 | + pop %eax | |
152 | + mov $0x77,%eax | |
153 | + int $0x80 | |
154 | + or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80. | |
155 | + | |
156 | + Checking for the code sequence should be somewhat reliable, because | |
157 | + the effect is to call the system call sigreturn. This is unlikely | |
158 | + to occur anywhere other than a signal trampoline. | |
159 | + | |
160 | + It kind of sucks that we have to read memory from the process in | |
161 | + order to identify a signal trampoline, but there doesn't seem to be | |
162 | + any other way. The IN_SIGTRAMP macro in tm-linux.h arranges to | |
163 | + only call us if no function name could be identified, which should | |
164 | + be the case since the code is on the stack. */ | |
165 | + | |
166 | + #define LINUX_SIGTRAMP_INSN0 (0x58) /* pop %eax */ | |
167 | + #define LINUX_SIGTRAMP_OFFSET0 (0) | |
168 | + #define LINUX_SIGTRAMP_INSN1 (0xb8) /* mov $NNNN,%eax */ | |
169 | + #define LINUX_SIGTRAMP_OFFSET1 (1) | |
170 | + #define LINUX_SIGTRAMP_INSN2 (0xcd) /* int */ | |
171 | + #define LINUX_SIGTRAMP_OFFSET2 (6) | |
172 | + | |
173 | + static const unsigned char linux_sigtramp_code[] = | |
174 | + { | |
175 | + LINUX_SIGTRAMP_INSN0, /* pop %eax */ | |
176 | + LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00, /* mov $0x77,%eax */ | |
177 | + LINUX_SIGTRAMP_INSN2, 0x80 /* int $0x80 */ | |
178 | + }; | |
179 | + | |
180 | + #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code) | |
181 | + | |
182 | + /* If PC is in a sigtramp routine, return the address of the start of | |
183 | + the routine. Otherwise, return 0. */ | |
184 | + | |
185 | + static CORE_ADDR | |
186 | + i386_linux_sigtramp_start (pc) | |
187 | + CORE_ADDR pc; | |
188 | + { | |
189 | + unsigned char buf[LINUX_SIGTRAMP_LEN]; | |
190 | + | |
191 | + /* We only recognize a signal trampoline if PC is at the start of | |
192 | + one of the three instructions. We optimize for finding the PC at | |
193 | + the start, as will be the case when the trampoline is not the | |
194 | + first frame on the stack. We assume that in the case where the | |
195 | + PC is not at the start of the instruction sequence, there will be | |
196 | + a few trailing readable bytes on the stack. */ | |
197 | + | |
198 | + if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0) | |
199 | + return 0; | |
200 | + | |
201 | + if (buf[0] != LINUX_SIGTRAMP_INSN0) | |
202 | + { | |
203 | + int adjust; | |
204 | + | |
205 | + switch (buf[0]) | |
206 | + { | |
207 | + case LINUX_SIGTRAMP_INSN1: | |
208 | + adjust = LINUX_SIGTRAMP_OFFSET1; | |
209 | + break; | |
210 | + case LINUX_SIGTRAMP_INSN2: | |
211 | + adjust = LINUX_SIGTRAMP_OFFSET2; | |
212 | + break; | |
213 | + default: | |
214 | + return 0; | |
215 | + } | |
216 | + | |
217 | + pc -= adjust; | |
218 | + | |
219 | + if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0) | |
220 | + return 0; | |
221 | + } | |
222 | + | |
223 | + if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0) | |
224 | + return 0; | |
225 | + | |
226 | + return pc; | |
227 | + } | |
228 | + | |
229 | + /* Return whether PC is in a Linux sigtramp routine. */ | |
230 | + | |
231 | + int | |
232 | + i386_linux_sigtramp (pc) | |
233 | + CORE_ADDR pc; | |
234 | + { | |
235 | + return i386_linux_sigtramp_start (pc) != 0; | |
236 | + } | |
237 | + | |
238 | + /* Assuming FRAME is for a Linux sigtramp routine, return the saved | |
239 | + program counter. The Linux kernel will set up a sigcontext | |
240 | + structure immediately before the sigtramp routine on the stack. */ | |
241 | + | |
242 | + CORE_ADDR | |
243 | + i386_linux_sigtramp_saved_pc (frame) | |
244 | + struct frame_info *frame; | |
245 | + { | |
246 | + CORE_ADDR pc; | |
247 | + | |
248 | + pc = i386_linux_sigtramp_start (frame->pc); | |
249 | + if (pc == 0) | |
250 | + error ("i386_linux_sigtramp_saved_pc called when no sigtramp"); | |
251 | + return read_memory_integer ((pc | |
252 | + - LINUX_SIGCONTEXT_SIZE | |
253 | + + LINUX_SIGCONTEXT_PC_OFFSET), | |
254 | + 4); | |
255 | + } | |
256 | + | |
257 | + /* Assuming FRAME is for a Linux sigtramp routine, return the saved | |
258 | + stack pointer. The Linux kernel will set up a sigcontext structure | |
259 | + immediately before the sigtramp routine on the stack. */ | |
260 | + | |
261 | + CORE_ADDR | |
262 | + i386_linux_sigtramp_saved_sp (frame) | |
263 | + struct frame_info *frame; | |
264 | + { | |
265 | + CORE_ADDR pc; | |
266 | + | |
267 | + pc = i386_linux_sigtramp_start (frame->pc); | |
268 | + if (pc == 0) | |
269 | + error ("i386_linux_sigtramp_saved_sp called when no sigtramp"); | |
270 | + return read_memory_integer ((pc | |
271 | + - LINUX_SIGCONTEXT_SIZE | |
272 | + + LINUX_SIGCONTEXT_SP_OFFSET), | |
273 | + 4); | |
274 | + } | |
275 | + | |
276 | + #endif /* I386_LINUX_SIGTRAMP */ | |
277 | + | |
278 | #ifdef STATIC_TRANSFORM_NAME | |
279 | /* SunPRO encodes the static variables. This is not related to C++ mangling, | |
280 | it is done for C too. */ |