Commit | Line | Data |
---|---|---|
7a7adcdf JB |
1 | /* Target-dependent code for Interix running on i386's, for GDB. |
2 | Copyright 2002 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GDB. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "arch-utils.h" | |
22 | ||
23 | #include "frame.h" | |
24 | #include "gdb_string.h" | |
25 | #include "gdb-stabs.h" | |
26 | #include "gdbcore.h" | |
27 | #include "gdbtypes.h" | |
28 | #include "i386-tdep.h" | |
29 | #include "inferior.h" | |
30 | #include "libbfd.h" | |
31 | #include "objfiles.h" | |
32 | #include "osabi.h" | |
33 | #include "regcache.h" | |
34 | ||
35 | /* offsetof (mcontext_t, gregs.gregs[EBP]) */ | |
36 | static const int mcontext_EBP_greg_offset = 180; | |
37 | ||
38 | /* offsetof (mcontext_t, gregs.gregs[EIP]) */ | |
39 | static const int mcontext_EIP_greg_offset = 184; | |
40 | ||
41 | /* offsetof (mcontext_t, gregs.gregs[UESP]) */ | |
42 | static const int mcontext_UESP_greg_offset = 196; | |
43 | ||
44 | /* offsetof (mcontext_t, gregs.reserved[1]) */ | |
45 | static const int mcontext_syscall_greg_offset = 4; | |
46 | ||
47 | /* offsetof (_JUMP_BUFFER, Eip) */ | |
48 | static const int jump_buffer_Eip_offset = 20; | |
49 | ||
50 | /* See procfs.c and *interix*.h in config/[alpha,i386]. */ | |
51 | /* ??? These should be static, but this needs a bit of work before this | |
52 | can be done. */ | |
53 | CORE_ADDR tramp_start; | |
54 | CORE_ADDR tramp_end; | |
55 | CORE_ADDR null_start; | |
56 | CORE_ADDR null_end; | |
57 | int winver; /* Windows NT version number */ | |
58 | ||
59 | /* Forward declarations. */ | |
60 | extern void _initialize_i386_interix_tdep (void); | |
61 | extern initialize_file_ftype _initialize_i386_interix_tdep; | |
62 | ||
63 | /* Adjust the section offsets in an objfile structure so that it's correct | |
64 | for the type of symbols being read (or undo it with the _restore | |
65 | arguments). | |
66 | ||
67 | If main programs ever start showing up at other than the default Image | |
68 | Base, this is where that would likely be applied. */ | |
69 | ||
70 | void | |
71 | pei_adjust_objfile_offsets (struct objfile *objfile, | |
72 | enum objfile_adjusts type) | |
73 | { | |
74 | int i; | |
75 | CORE_ADDR symbols_offset; | |
76 | ||
77 | switch (type) | |
78 | { | |
79 | case adjust_for_symtab: | |
80 | symbols_offset = NONZERO_LINK_BASE (objfile->obfd); | |
81 | break; | |
82 | case adjust_for_symtab_restore: | |
83 | symbols_offset = -NONZERO_LINK_BASE (objfile->obfd); | |
84 | break; | |
85 | case adjust_for_stabs: | |
86 | case adjust_for_stabs_restore: | |
87 | case adjust_for_dwarf: | |
88 | case adjust_for_dwarf_restore: | |
89 | default: | |
90 | return; | |
91 | } | |
92 | ||
a39a16c4 | 93 | for (i = 0; i < objfile->num_sections; i++) |
7a7adcdf JB |
94 | { |
95 | (objfile->section_offsets)->offsets[i] += symbols_offset; | |
96 | } | |
97 | } | |
98 | ||
99 | static int | |
100 | i386_interix_pc_in_sigtramp (CORE_ADDR pc, char *name) | |
101 | { | |
102 | /* This is sufficient, where used, but is NOT a complete test; There | |
e9582e71 AC |
103 | is more in DEPRECATED_INIT_EXTRA_FRAME_INFO |
104 | (a.k.a. interix_back_one_frame). */ | |
7a7adcdf JB |
105 | return ((pc >= tramp_start && pc < tramp_end) |
106 | || (pc >= null_start && pc < null_end)); | |
107 | } | |
108 | ||
109 | static int | |
110 | i386_interix_in_solib_call_trampoline (CORE_ADDR pc, char *name) | |
111 | { | |
112 | return i386_pe_skip_trampoline_code (pc, name); | |
113 | } | |
114 | ||
115 | static CORE_ADDR | |
116 | i386_interix_skip_trampoline_code (CORE_ADDR pc) | |
117 | { | |
118 | return i386_pe_skip_trampoline_code (pc, 0); | |
119 | } | |
120 | ||
7a7adcdf JB |
121 | static int |
122 | i386_interix_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe) | |
123 | { | |
124 | /* In the context where this is used, we get the saved PC before we've | |
125 | successfully unwound far enough to be sure what we've got (it may | |
126 | be a signal handler caller). If we're dealing with a signal | |
127 | handler caller, this will return valid, which is fine. If not, | |
128 | it'll make the correct test. */ | |
5a203e44 | 129 | return ((get_frame_type (thisframe) == SIGTRAMP_FRAME) |
7a7adcdf | 130 | || (chain != 0 |
627b3ba2 AC |
131 | && !deprecated_inside_entry_file (read_memory_integer |
132 | (thisframe->frame + 4, 4)))); | |
7a7adcdf JB |
133 | } |
134 | ||
5a203e44 AC |
135 | /* We want to find the previous frame, which on Interix is tricky when |
136 | signals are involved; set frame->frame appropriately, and also get | |
137 | the pc and tweak tye frame's type; this replaces a boatload of | |
138 | nested macros, as well. */ | |
7a7adcdf JB |
139 | static void |
140 | i386_interix_back_one_frame (int fromleaf, struct frame_info *frame) | |
141 | { | |
142 | CORE_ADDR ra; | |
143 | CORE_ADDR fm; | |
144 | CORE_ADDR context; | |
145 | long t; | |
146 | ||
147 | if (frame == NULL) | |
148 | internal_error (__FILE__, __LINE__, "unexpected NULL frame"); | |
149 | ||
150 | if (fromleaf) | |
151 | { | |
6913c89a | 152 | frame->pc = DEPRECATED_SAVED_PC_AFTER_CALL (frame->next); |
7a7adcdf JB |
153 | return; |
154 | } | |
155 | ||
156 | if (!frame->next) | |
157 | { | |
158 | frame->pc = read_pc (); | |
159 | ||
160 | /* Part of the signal stuff... See below. */ | |
161 | if (stopped_by_random_signal) | |
162 | { | |
163 | /* We know we're in a system call mini-frame; was it | |
164 | NullApi or something else? */ | |
6913c89a | 165 | ra = DEPRECATED_SAVED_PC_AFTER_CALL (frame); |
7a7adcdf | 166 | if (ra >= null_start && ra < null_end) |
5a203e44 | 167 | deprecated_set_frame_type (frame, SIGTRAMP_FRAME); |
7a7adcdf JB |
168 | /* There might also be an indirect call to the mini-frame, |
169 | putting one more return address on the stack. (XP only, | |
170 | I think?) This can't (reasonably) return the address of the | |
171 | signal handler caller unless it's that situation, so this | |
172 | is safe. */ | |
173 | ra = read_memory_unsigned_integer (read_register (SP_REGNUM) + 4, 4); | |
174 | if (ra >= null_start && ra < null_end) | |
5a203e44 | 175 | deprecated_set_frame_type (frame, SIGTRAMP_FRAME); |
7a7adcdf JB |
176 | } |
177 | return; | |
178 | } | |
179 | ||
5a203e44 | 180 | if (!(get_frame_type (frame->next) == SIGTRAMP_FRAME)) |
7a7adcdf JB |
181 | { |
182 | frame->pc = read_memory_integer (frame->next->frame + 4, 4); | |
183 | return; | |
184 | } | |
185 | ||
186 | /* This is messy (actually AWFUL)... The "trampoline" might be 2, 3 | |
187 | or all 5 entities on the frame. | |
188 | ||
189 | Chunk 1 will be present when we're actually in a signal handler. | |
190 | Chunk 2 will be present when an asynchronous signal (one that | |
191 | didn't come in with a system call) is present. | |
192 | We may not (yet) be in the handler, if we're just returning | |
193 | from the call. | |
194 | When we're actually in a handler taken from an asynchronous | |
195 | signal, both will be present. | |
196 | ||
197 | Chunk 1: | |
198 | PdxSignalDeliverer's frame | |
199 | + Context struct -- not accounted for in any frame | |
200 | ||
201 | Chunk 2: | |
202 | + PdxNullPosixApi's frame | |
203 | + PdxNullApiCaller's frame | |
204 | + Context struct = 0x230 not accounted for in any frame | |
205 | ||
206 | The symbol names come from examining objdumps of psxdll.dll; | |
207 | they don't appear in the runtime image. | |
208 | ||
209 | For gdb's purposes, we can pile all this into one frame. */ | |
210 | ||
211 | ra = frame->next->pc; | |
212 | /* Are we already pointing at PdxNullPosixApi? We are if | |
213 | this is a signal frame, we're at next-to-top, and were stopped | |
214 | by a random signal (if it wasn't the right address under | |
215 | these circumstances, we wouldn't be here at all by tests above | |
216 | on the prior frame). */ | |
217 | if (frame->next->next == NULL && stopped_by_random_signal) | |
218 | { | |
219 | /* We're pointing at the frame FOR PdxNullApi. */ | |
220 | fm = frame->frame; | |
221 | } | |
222 | else | |
223 | { | |
224 | /* No... We must be pointing at the frame that was called | |
225 | by PdxSignalDeliverer; back up across the whole mess. */ | |
226 | ||
618ce49f AC |
227 | /* Extract the frame for PdxSignalDeliverer. Note: |
228 | DEPRECATED_FRAME_CHAIN used the "old" frame pointer because | |
229 | we were a deliverer. Get the address of the context record | |
230 | that's on here frameless. */ | |
7a7adcdf JB |
231 | context = read_memory_integer (frame->frame, 4); /* an Arg */ |
232 | ||
233 | /* Now extract the frame pointer contained in the context. */ | |
234 | fm = read_memory_integer (context + mcontext_EBP_greg_offset, 4); | |
235 | ||
236 | ra = read_memory_integer (context + mcontext_EIP_greg_offset, 4); | |
237 | ||
238 | /* We need to know if we're in a system call because we'll be | |
239 | in a syscall mini-frame, if so, and the rules are different. */ | |
240 | t = (long) read_memory_integer (context + mcontext_syscall_greg_offset, | |
241 | 4); | |
242 | /* t contains 0 if running free, 1 if blocked on a system call, | |
243 | and 2 if blocked on an exception message (e.g. a trap); | |
244 | we don't expect to get here with a 2. */ | |
245 | if (t != 1) | |
246 | { | |
247 | /* Not at a system call, therefore it can't be NullApi. */ | |
248 | frame->pc = ra; | |
249 | frame->frame = fm; | |
250 | return; | |
251 | } | |
252 | ||
253 | /* It's a system call... Mini frame, then look for NullApi. */ | |
254 | /* Get the RA (on the stack) associated with this... It's | |
255 | a system call mini-frame. */ | |
256 | ra = read_memory_integer (context + mcontext_UESP_greg_offset, 4); | |
257 | ||
258 | if (winver >= 51) | |
259 | { | |
260 | /* Newer versions of Windows NT interpose another return | |
261 | address (but no other "stack frame" stuff) that we need | |
262 | to simply ignore here. */ | |
263 | ra += 4; | |
264 | } | |
265 | ||
266 | ra = read_memory_integer (ra, 4); | |
267 | ||
268 | if (!(ra >= null_start && ra < null_end)) | |
269 | { | |
270 | /* No Null API present; we're done. */ | |
271 | frame->pc = ra; | |
272 | frame->frame = fm; | |
273 | return; | |
274 | } | |
275 | } | |
276 | ||
277 | /* At this point, we're looking at the frame for PdxNullPosixApi, | |
278 | in either case. | |
279 | ||
280 | PdxNullPosixApi is called by PdxNullApiCaller (which in turn | |
281 | is called by _PdxNullApiCaller (note the _).) | |
282 | PdxNullPosixApiCaller (no _) is a frameless function. | |
283 | ||
284 | The saved frame pointer is as fm, but it's not of interest | |
285 | to us because it skips us over the saved context, which is | |
286 | the wrong thing to do, because it skips the interrrupted | |
287 | routine! PdxNullApiCaller takes as its only argument the | |
288 | address of the context of the interrupded function (which | |
289 | is really in no frame, but jammed on the stack by the system) | |
290 | ||
291 | So: fm+0: saved bp | |
292 | fm+4: return address to _PdxNullApiCaller | |
293 | fm+8: arg to PdxNullApiCaller pushed by _Pdx... */ | |
294 | ||
295 | fm = read_memory_integer (fm + 0x8, 4); | |
296 | ||
297 | /* Extract the second context record. */ | |
298 | ||
299 | ra = read_memory_integer (fm + mcontext_EIP_greg_offset, 4); | |
300 | fm = read_memory_integer (fm + mcontext_EBP_greg_offset, 4); | |
301 | ||
302 | frame->frame = fm; | |
303 | frame->pc = ra; | |
304 | ||
305 | return; | |
306 | } | |
307 | ||
308 | static CORE_ADDR | |
309 | i386_interix_frame_saved_pc (struct frame_info *fi) | |
310 | { | |
311 | /* Assume that we've already unwound enough to have the caller's address | |
312 | if we're dealing with a signal handler caller (And if that fails, | |
313 | return 0). */ | |
5a203e44 | 314 | if ((get_frame_type (fi) == SIGTRAMP_FRAME)) |
7a7adcdf JB |
315 | return fi->next ? fi->next->pc : 0; |
316 | else | |
317 | return read_memory_integer (fi->frame + 4, 4); | |
318 | } | |
319 | ||
320 | static void | |
321 | i386_interix_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
322 | { | |
323 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); | |
324 | ||
325 | tdep->struct_return = reg_struct_return; | |
326 | tdep->jb_pc_offset = jump_buffer_Eip_offset; | |
327 | ||
f561f026 | 328 | set_gdbarch_deprecated_pc_in_sigtramp (gdbarch, i386_interix_pc_in_sigtramp); |
7a7adcdf JB |
329 | set_gdbarch_in_solib_call_trampoline (gdbarch, |
330 | i386_interix_in_solib_call_trampoline); | |
331 | set_gdbarch_skip_trampoline_code (gdbarch, | |
332 | i386_interix_skip_trampoline_code); | |
e9582e71 | 333 | set_gdbarch_deprecated_init_extra_frame_info (gdbarch, i386_interix_back_one_frame); |
618ce49f | 334 | set_gdbarch_deprecated_frame_chain_valid (gdbarch, i386_interix_frame_chain_valid); |
8bedc050 | 335 | set_gdbarch_deprecated_frame_saved_pc (gdbarch, i386_interix_frame_saved_pc); |
7a7adcdf JB |
336 | set_gdbarch_name_of_malloc (gdbarch, "_malloc"); |
337 | } | |
338 | ||
339 | static enum gdb_osabi | |
340 | i386_interix_osabi_sniffer (bfd * abfd) | |
341 | { | |
342 | char *target_name = bfd_get_target (abfd); | |
343 | ||
344 | if (strcmp (target_name, "pei-i386") == 0) | |
345 | return GDB_OSABI_INTERIX; | |
346 | ||
347 | return GDB_OSABI_UNKNOWN; | |
348 | } | |
349 | ||
350 | void | |
351 | _initialize_i386_interix_tdep (void) | |
352 | { | |
353 | gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour, | |
354 | i386_interix_osabi_sniffer); | |
355 | ||
05816f70 | 356 | gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_INTERIX, |
7a7adcdf JB |
357 | i386_interix_init_abi); |
358 | } |