Commit | Line | Data |
---|---|---|
ed504bdf MK |
1 | /* Target-dependent code for NetBSD/i386. |
2 | ||
6aba47ca DJ |
3 | Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, 2003, |
4 | 2004, 2007 Free Software Foundation, Inc. | |
0fc93e6b C |
5 | |
6 | This file is part of GDB. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
a9762ec7 | 10 | the Free Software Foundation; either version 3 of the License, or |
0fc93e6b C |
11 | (at your option) any later version. |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
0fc93e6b C |
20 | |
21 | #include "defs.h" | |
13739f4d | 22 | #include "arch-utils.h" |
911bc6ee | 23 | #include "frame.h" |
dfe6eb1f JT |
24 | #include "gdbcore.h" |
25 | #include "regcache.h" | |
13739f4d | 26 | #include "regset.h" |
4be87837 | 27 | #include "osabi.h" |
911bc6ee | 28 | #include "symtab.h" |
0fc93e6b | 29 | |
13739f4d MK |
30 | #include "gdb_assert.h" |
31 | #include "gdb_string.h" | |
32 | ||
3cac699e | 33 | #include "i386-tdep.h" |
dfe6eb1f | 34 | #include "i387-tdep.h" |
3cac699e | 35 | #include "nbsd-tdep.h" |
7d400e77 JT |
36 | #include "solib-svr4.h" |
37 | ||
13739f4d MK |
38 | /* From <machine/reg.h>. */ |
39 | static int i386nbsd_r_reg_offset[] = | |
dfe6eb1f | 40 | { |
13739f4d MK |
41 | 0 * 4, /* %eax */ |
42 | 1 * 4, /* %ecx */ | |
43 | 2 * 4, /* %edx */ | |
44 | 3 * 4, /* %ebx */ | |
45 | 4 * 4, /* %esp */ | |
46 | 5 * 4, /* %ebp */ | |
47 | 6 * 4, /* %esi */ | |
48 | 7 * 4, /* %edi */ | |
49 | 8 * 4, /* %eip */ | |
50 | 9 * 4, /* %eflags */ | |
51 | 10 * 4, /* %cs */ | |
52 | 11 * 4, /* %ss */ | |
53 | 12 * 4, /* %ds */ | |
54 | 13 * 4, /* %es */ | |
55 | 14 * 4, /* %fs */ | |
56 | 15 * 4 /* %gs */ | |
dfe6eb1f JT |
57 | }; |
58 | ||
d66198e1 JT |
59 | /* Under NetBSD/i386, signal handler invocations can be identified by the |
60 | designated code sequence that is used to return from a signal handler. | |
61 | In particular, the return address of a signal handler points to the | |
62 | following code sequence: | |
63 | ||
64 | leal 0x10(%esp), %eax | |
65 | pushl %eax | |
66 | pushl %eax | |
67 | movl $0x127, %eax # __sigreturn14 | |
68 | int $0x80 | |
69 | ||
70 | Each instruction has a unique encoding, so we simply attempt to match | |
71 | the instruction the PC is pointing to with any of the above instructions. | |
72 | If there is a hit, we know the offset to the start of the designated | |
73 | sequence and can then check whether we really are executing in the | |
74 | signal trampoline. If not, -1 is returned, otherwise the offset from the | |
75 | start of the return sequence is returned. */ | |
76 | #define RETCODE_INSN1 0x8d | |
77 | #define RETCODE_INSN2 0x50 | |
78 | #define RETCODE_INSN3 0x50 | |
79 | #define RETCODE_INSN4 0xb8 | |
80 | #define RETCODE_INSN5 0xcd | |
81 | ||
82 | #define RETCODE_INSN2_OFF 4 | |
83 | #define RETCODE_INSN3_OFF 5 | |
84 | #define RETCODE_INSN4_OFF 6 | |
85 | #define RETCODE_INSN5_OFF 11 | |
86 | ||
87 | static const unsigned char sigtramp_retcode[] = | |
3cac699e | 88 | { |
d66198e1 JT |
89 | RETCODE_INSN1, 0x44, 0x24, 0x10, |
90 | RETCODE_INSN2, | |
91 | RETCODE_INSN3, | |
92 | RETCODE_INSN4, 0x27, 0x01, 0x00, 0x00, | |
93 | RETCODE_INSN5, 0x80, | |
94 | }; | |
95 | ||
96 | static LONGEST | |
24f9f5e3 | 97 | i386nbsd_sigtramp_offset (struct frame_info *next_frame) |
d66198e1 | 98 | { |
24f9f5e3 | 99 | CORE_ADDR pc = frame_pc_unwind (next_frame); |
d66198e1 JT |
100 | unsigned char ret[sizeof(sigtramp_retcode)], insn; |
101 | LONGEST off; | |
102 | int i; | |
103 | ||
24f9f5e3 | 104 | if (!safe_frame_unwind_memory (next_frame, pc, &insn, 1)) |
d66198e1 JT |
105 | return -1; |
106 | ||
107 | switch (insn) | |
108 | { | |
109 | case RETCODE_INSN1: | |
110 | off = 0; | |
111 | break; | |
112 | ||
113 | case RETCODE_INSN2: | |
114 | /* INSN2 and INSN3 are the same. Read at the location of PC+1 | |
115 | to determine if we're actually looking at INSN2 or INSN3. */ | |
24f9f5e3 | 116 | if (!safe_frame_unwind_memory (next_frame, pc + 1, &insn, 1)) |
d66198e1 JT |
117 | return -1; |
118 | ||
119 | if (insn == RETCODE_INSN3) | |
120 | off = RETCODE_INSN2_OFF; | |
121 | else | |
122 | off = RETCODE_INSN3_OFF; | |
123 | break; | |
3cac699e | 124 | |
d66198e1 JT |
125 | case RETCODE_INSN4: |
126 | off = RETCODE_INSN4_OFF; | |
127 | break; | |
128 | ||
129 | case RETCODE_INSN5: | |
130 | off = RETCODE_INSN5_OFF; | |
131 | break; | |
132 | ||
133 | default: | |
134 | return -1; | |
135 | } | |
136 | ||
137 | pc -= off; | |
3cac699e | 138 | |
24f9f5e3 | 139 | if (!safe_frame_unwind_memory (next_frame, pc, ret, sizeof (ret))) |
d66198e1 | 140 | return -1; |
3cac699e | 141 | |
d66198e1 JT |
142 | if (memcmp (ret, sigtramp_retcode, sizeof (ret)) == 0) |
143 | return off; | |
144 | ||
145 | return -1; | |
3cac699e JT |
146 | } |
147 | ||
377d9ebd | 148 | /* Return whether the frame preceding NEXT_FRAME corresponds to a |
911bc6ee MK |
149 | NetBSD sigtramp routine. */ |
150 | ||
d66198e1 | 151 | static int |
911bc6ee | 152 | i386nbsd_sigtramp_p (struct frame_info *next_frame) |
d66198e1 | 153 | { |
911bc6ee MK |
154 | CORE_ADDR pc = frame_pc_unwind (next_frame); |
155 | char *name; | |
156 | ||
157 | find_pc_partial_function (pc, &name, NULL, NULL); | |
d66198e1 | 158 | return (nbsd_pc_in_sigtramp (pc, name) |
24f9f5e3 | 159 | || i386nbsd_sigtramp_offset (next_frame) >= 0); |
d66198e1 | 160 | } |
3cac699e JT |
161 | |
162 | /* From <machine/signal.h>. */ | |
13739f4d | 163 | int i386nbsd_sc_reg_offset[] = |
a3386186 MK |
164 | { |
165 | 10 * 4, /* %eax */ | |
166 | 9 * 4, /* %ecx */ | |
167 | 8 * 4, /* %edx */ | |
168 | 7 * 4, /* %ebx */ | |
169 | 14 * 4, /* %esp */ | |
170 | 6 * 4, /* %ebp */ | |
171 | 5 * 4, /* %esi */ | |
172 | 4 * 4, /* %edi */ | |
173 | 11 * 4, /* %eip */ | |
174 | 13 * 4, /* %eflags */ | |
175 | 12 * 4, /* %cs */ | |
176 | 15 * 4, /* %ss */ | |
177 | 3 * 4, /* %ds */ | |
178 | 2 * 4, /* %es */ | |
179 | 1 * 4, /* %fs */ | |
180 | 0 * 4 /* %gs */ | |
181 | }; | |
3cac699e JT |
182 | |
183 | static void | |
184 | i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
185 | { | |
186 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); | |
187 | ||
188 | /* Obviously NetBSD is BSD-based. */ | |
189 | i386bsd_init_abi (info, gdbarch); | |
190 | ||
13739f4d MK |
191 | /* NetBSD has a different `struct reg'. */ |
192 | tdep->gregset_reg_offset = i386nbsd_r_reg_offset; | |
193 | tdep->gregset_num_regs = ARRAY_SIZE (i386nbsd_r_reg_offset); | |
194 | tdep->sizeof_gregset = 16 * 4; | |
195 | ||
3cac699e | 196 | /* NetBSD has different signal trampoline conventions. */ |
911bc6ee MK |
197 | tdep->sigtramp_start = 0; |
198 | tdep->sigtramp_end = 0; | |
199 | tdep->sigtramp_p = i386nbsd_sigtramp_p; | |
3cac699e JT |
200 | |
201 | /* NetBSD uses -freg-struct-return by default. */ | |
202 | tdep->struct_return = reg_struct_return; | |
203 | ||
3cac699e | 204 | /* NetBSD has a `struct sigcontext' that's different from the |
f2e7c15d | 205 | original 4.3 BSD. */ |
a3386186 | 206 | tdep->sc_reg_offset = i386nbsd_sc_reg_offset; |
13739f4d MK |
207 | tdep->sc_num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset); |
208 | } | |
209 | ||
3cac699e | 210 | /* NetBSD ELF. */ |
13739f4d | 211 | |
3cac699e JT |
212 | static void |
213 | i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
214 | { | |
215 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); | |
216 | ||
217 | /* It's still NetBSD. */ | |
218 | i386nbsd_init_abi (info, gdbarch); | |
219 | ||
220 | /* But ELF-based. */ | |
221 | i386_elf_init_abi (info, gdbarch); | |
222 | ||
223 | /* NetBSD ELF uses SVR4-style shared libraries. */ | |
13739f4d | 224 | set_solib_svr4_fetch_link_map_offsets |
7e654c37 | 225 | (gdbarch, svr4_ilp32_fetch_link_map_offsets); |
3cac699e JT |
226 | |
227 | /* NetBSD ELF uses -fpcc-struct-return by default. */ | |
228 | tdep->struct_return = pcc_struct_return; | |
3cac699e JT |
229 | } |
230 | ||
dfe6eb1f JT |
231 | void |
232 | _initialize_i386nbsd_tdep (void) | |
233 | { | |
05816f70 | 234 | gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_ELF, |
3cac699e | 235 | i386nbsdelf_init_abi); |
dfe6eb1f | 236 | } |