Commit | Line | Data |
---|---|---|
bb7e3f4d YQ |
1 | /* Target-dependent code for SDE on MIPS processors. |
2 | ||
42a4f53d | 3 | Copyright (C) 2014-2019 Free Software Foundation, Inc. |
bb7e3f4d YQ |
4 | |
5 | This file is part of GDB. | |
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 | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include "defs.h" | |
21 | #include "osabi.h" | |
22 | #include "elf-bfd.h" | |
23 | #include "block.h" | |
24 | #include "symtab.h" | |
25 | ||
26 | #include "frame.h" | |
27 | #include "frame-unwind.h" | |
28 | #include "frame-base.h" | |
29 | #include "trad-frame.h" | |
30 | ||
31 | #include "mips-tdep.h" | |
32 | ||
33 | /* Fill in the register cache *THIS_CACHE for THIS_FRAME for use | |
34 | in the SDE frame unwinder. */ | |
35 | ||
36 | static struct trad_frame_cache * | |
37 | mips_sde_frame_cache (struct frame_info *this_frame, void **this_cache) | |
38 | { | |
39 | struct gdbarch *gdbarch = get_frame_arch (this_frame); | |
40 | const struct mips_regnum *regs = mips_regnum (gdbarch); | |
41 | const int sizeof_reg_t = mips_abi_regsize (gdbarch); | |
42 | enum mips_abi abi = mips_abi (gdbarch); | |
43 | struct trad_frame_cache *cache; | |
44 | CORE_ADDR xcpt_frame; | |
45 | CORE_ADDR start_addr; | |
46 | CORE_ADDR stack_addr; | |
47 | CORE_ADDR pc; | |
48 | int i; | |
49 | ||
50 | if (*this_cache != NULL) | |
19ba03f4 | 51 | return (struct trad_frame_cache *) *this_cache; |
bb7e3f4d YQ |
52 | cache = trad_frame_cache_zalloc (this_frame); |
53 | *this_cache = cache; | |
54 | ||
55 | /* The previous registers are held in struct xcptcontext | |
56 | which is at $sp+offs | |
57 | ||
58 | struct xcptcontext { | |
59 | reg_t sr; CP0 Status | |
60 | reg_t cr; CP0 Cause | |
61 | reg_t epc; CP0 EPC | |
62 | reg_t vaddr; CP0 BadVAddr | |
63 | reg_t regs[32]; General registers | |
64 | reg_t mdlo; LO | |
65 | reg_t mdhi; HI | |
66 | reg_t mdex; ACX | |
67 | ... | |
68 | }; | |
69 | */ | |
70 | ||
71 | stack_addr = get_frame_register_signed (this_frame, | |
72 | gdbarch_sp_regnum (gdbarch)); | |
73 | switch (abi) | |
74 | { | |
75 | case MIPS_ABI_O32: | |
76 | /* 40: XCPTCONTEXT | |
77 | 24: xcpt_gen() argspace (16 bytes) | |
78 | 16: _xcptcall() saved ra, rounded up ( 8 bytes) | |
79 | 00: _xcptcall() argspace (16 bytes) */ | |
80 | xcpt_frame = stack_addr + 40; | |
81 | break; | |
82 | case MIPS_ABI_N32: | |
83 | case MIPS_ABI_N64: | |
84 | default: /* Wild guess. */ | |
85 | /* 16: XCPTCONTEXT | |
86 | 16: xcpt_gen() argspace ( 0 bytes) | |
87 | 00: _xcptcall() saved ra, rounded up (16 bytes) */ | |
88 | xcpt_frame = stack_addr + 16; | |
89 | break; | |
90 | } | |
91 | ||
92 | trad_frame_set_reg_addr (cache, | |
93 | MIPS_PS_REGNUM + gdbarch_num_regs (gdbarch), | |
94 | xcpt_frame + 0 * sizeof_reg_t); | |
95 | trad_frame_set_reg_addr (cache, | |
96 | regs->cause + gdbarch_num_regs (gdbarch), | |
97 | xcpt_frame + 1 * sizeof_reg_t); | |
98 | trad_frame_set_reg_addr (cache, | |
99 | regs->pc + gdbarch_num_regs (gdbarch), | |
100 | xcpt_frame + 2 * sizeof_reg_t); | |
101 | trad_frame_set_reg_addr (cache, | |
102 | regs->badvaddr + gdbarch_num_regs (gdbarch), | |
103 | xcpt_frame + 3 * sizeof_reg_t); | |
104 | for (i = 0; i < MIPS_NUMREGS; i++) | |
105 | trad_frame_set_reg_addr (cache, | |
106 | i + MIPS_ZERO_REGNUM + gdbarch_num_regs (gdbarch), | |
107 | xcpt_frame + (4 + i) * sizeof_reg_t); | |
108 | trad_frame_set_reg_addr (cache, | |
109 | regs->lo + gdbarch_num_regs (gdbarch), | |
110 | xcpt_frame + 36 * sizeof_reg_t); | |
111 | trad_frame_set_reg_addr (cache, | |
112 | regs->hi + gdbarch_num_regs (gdbarch), | |
113 | xcpt_frame + 37 * sizeof_reg_t); | |
114 | ||
115 | pc = get_frame_pc (this_frame); | |
116 | find_pc_partial_function (pc, NULL, &start_addr, NULL); | |
117 | trad_frame_set_id (cache, frame_id_build (start_addr, stack_addr)); | |
118 | ||
119 | return cache; | |
120 | } | |
121 | ||
122 | /* Implement the this_id function for the SDE frame unwinder. */ | |
123 | ||
124 | static void | |
125 | mips_sde_frame_this_id (struct frame_info *this_frame, void **this_cache, | |
126 | struct frame_id *this_id) | |
127 | { | |
128 | struct trad_frame_cache *this_trad_cache | |
129 | = mips_sde_frame_cache (this_frame, this_cache); | |
130 | ||
131 | trad_frame_get_id (this_trad_cache, this_id); | |
132 | } | |
133 | ||
134 | /* Implement the prev_register function for the SDE frame unwinder. */ | |
135 | ||
136 | static struct value * | |
137 | mips_sde_frame_prev_register (struct frame_info *this_frame, | |
138 | void **this_cache, | |
139 | int prev_regnum) | |
140 | { | |
141 | struct trad_frame_cache *trad_cache | |
142 | = mips_sde_frame_cache (this_frame, this_cache); | |
143 | ||
144 | return trad_frame_get_register (trad_cache, this_frame, prev_regnum); | |
145 | } | |
146 | ||
147 | /* Implement the sniffer function for the SDE frame unwinder. */ | |
148 | ||
149 | static int | |
150 | mips_sde_frame_sniffer (const struct frame_unwind *self, | |
151 | struct frame_info *this_frame, | |
152 | void **this_cache) | |
153 | { | |
154 | CORE_ADDR pc = get_frame_pc (this_frame); | |
155 | const char *name; | |
156 | ||
157 | find_pc_partial_function (pc, &name, NULL, NULL); | |
158 | return (name | |
159 | && (strcmp (name, "_xcptcall") == 0 | |
160 | || strcmp (name, "_sigtramp") == 0)); | |
161 | } | |
162 | ||
163 | /* Data structure for the SDE frame unwinder. */ | |
164 | ||
165 | static const struct frame_unwind mips_sde_frame_unwind = | |
166 | { | |
167 | SIGTRAMP_FRAME, | |
168 | default_frame_unwind_stop_reason, | |
169 | mips_sde_frame_this_id, | |
170 | mips_sde_frame_prev_register, | |
171 | NULL, | |
172 | mips_sde_frame_sniffer | |
173 | }; | |
174 | ||
175 | /* Implement the this_base, this_locals, and this_args hooks | |
176 | for the normal unwinder. */ | |
177 | ||
178 | static CORE_ADDR | |
179 | mips_sde_frame_base_address (struct frame_info *this_frame, void **this_cache) | |
180 | { | |
181 | struct trad_frame_cache *this_trad_cache | |
182 | = mips_sde_frame_cache (this_frame, this_cache); | |
183 | ||
184 | return trad_frame_get_this_base (this_trad_cache); | |
185 | } | |
186 | ||
187 | static const struct frame_base mips_sde_frame_base = | |
188 | { | |
189 | &mips_sde_frame_unwind, | |
190 | mips_sde_frame_base_address, | |
191 | mips_sde_frame_base_address, | |
192 | mips_sde_frame_base_address | |
193 | }; | |
194 | ||
195 | static const struct frame_base * | |
196 | mips_sde_frame_base_sniffer (struct frame_info *this_frame) | |
197 | { | |
198 | if (mips_sde_frame_sniffer (&mips_sde_frame_unwind, this_frame, NULL)) | |
199 | return &mips_sde_frame_base; | |
200 | else | |
201 | return NULL; | |
202 | } | |
203 | ||
204 | static void | |
205 | mips_sde_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, | |
206 | void *obj) | |
207 | { | |
19ba03f4 | 208 | enum gdb_osabi *os_ident_ptr = (enum gdb_osabi *) obj; |
bb7e3f4d YQ |
209 | const char *name; |
210 | ||
fd361982 | 211 | name = bfd_section_name (sect); |
bb7e3f4d YQ |
212 | |
213 | /* The presence of a section with a ".sde" prefix is indicative | |
214 | of an SDE binary. */ | |
61012eef | 215 | if (startswith (name, ".sde")) |
bb7e3f4d YQ |
216 | *os_ident_ptr = GDB_OSABI_SDE; |
217 | } | |
218 | ||
219 | /* OSABI sniffer for MIPS SDE. */ | |
220 | ||
221 | static enum gdb_osabi | |
222 | mips_sde_elf_osabi_sniffer (bfd *abfd) | |
223 | { | |
224 | enum gdb_osabi osabi = GDB_OSABI_UNKNOWN; | |
225 | unsigned int elfosabi; | |
226 | ||
227 | /* If the generic sniffer gets a hit, return and let other sniffers | |
228 | get a crack at it. */ | |
229 | bfd_map_over_sections (abfd, | |
230 | generic_elf_osabi_sniff_abi_tag_sections, | |
231 | &osabi); | |
232 | if (osabi != GDB_OSABI_UNKNOWN) | |
233 | return GDB_OSABI_UNKNOWN; | |
234 | ||
235 | elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI]; | |
236 | ||
237 | if (elfosabi == ELFOSABI_NONE) | |
238 | { | |
239 | /* When elfosabi is ELFOSABI_NONE (0), then the ELF structures in the | |
240 | file are conforming to the base specification for that machine | |
241 | (there are no OS-specific extensions). In order to determine the | |
242 | real OS in use we must look for OS notes that have been added. | |
243 | ||
244 | For SDE, we simply look for sections named with .sde as prefixes. */ | |
245 | bfd_map_over_sections (abfd, | |
246 | mips_sde_elf_osabi_sniff_abi_tag_sections, | |
247 | &osabi); | |
248 | } | |
249 | return osabi; | |
250 | } | |
251 | ||
252 | static void | |
253 | mips_sde_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
254 | { | |
255 | frame_unwind_append_unwinder (gdbarch, &mips_sde_frame_unwind); | |
256 | frame_base_append_sniffer (gdbarch, mips_sde_frame_base_sniffer); | |
257 | } | |
258 | ||
bb7e3f4d YQ |
259 | void |
260 | _initialize_mips_sde_tdep (void) | |
261 | { | |
262 | gdbarch_register_osabi_sniffer (bfd_arch_mips, | |
263 | bfd_target_elf_flavour, | |
264 | mips_sde_elf_osabi_sniffer); | |
265 | ||
266 | gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_SDE, mips_sde_init_abi); | |
267 | } |