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