Commit | Line | Data |
---|---|---|
7176dfd2 JB |
1 | /* Target-dependent code for FreeBSD/arm. |
2 | ||
b811d2c2 | 3 | Copyright (C) 2017-2020 Free Software Foundation, Inc. |
7176dfd2 JB |
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 | ||
4de283e4 | 22 | #include "elf/common.h" |
d105cce5 AH |
23 | #include "target-descriptions.h" |
24 | #include "aarch32-tdep.h" | |
d55e5aa6 | 25 | #include "arm-tdep.h" |
4de283e4 | 26 | #include "arm-fbsd-tdep.h" |
7176dfd2 JB |
27 | #include "auxv.h" |
28 | #include "fbsd-tdep.h" | |
29 | #include "gdbcore.h" | |
30 | #include "osabi.h" | |
31 | #include "solib-svr4.h" | |
32 | #include "trad-frame.h" | |
33 | #include "tramp-frame.h" | |
34 | ||
7054e2ff JB |
35 | /* Register maps. */ |
36 | ||
37 | static const struct regcache_map_entry arm_fbsd_gregmap[] = | |
38 | { | |
39 | { 13, ARM_A1_REGNUM, 4 }, /* r0 ... r12 */ | |
40 | { 1, ARM_SP_REGNUM, 4 }, | |
41 | { 1, ARM_LR_REGNUM, 4 }, | |
42 | { 1, ARM_PC_REGNUM, 4 }, | |
43 | { 1, ARM_PS_REGNUM, 4 }, | |
44 | { 0 } | |
45 | }; | |
46 | ||
47 | static const struct regcache_map_entry arm_fbsd_vfpregmap[] = | |
48 | { | |
49 | { 32, ARM_D0_REGNUM, 8 }, /* d0 ... d31 */ | |
50 | { 1, ARM_FPSCR_REGNUM, 4 }, | |
51 | { 0 } | |
52 | }; | |
53 | ||
7176dfd2 JB |
54 | /* In a signal frame, sp points to a 'struct sigframe' which is |
55 | defined as: | |
56 | ||
57 | struct sigframe { | |
58 | siginfo_t sf_si; | |
59 | ucontext_t sf_uc; | |
60 | mcontext_vfp_t sf_vfp; | |
61 | }; | |
62 | ||
63 | ucontext_t is defined as: | |
64 | ||
65 | struct __ucontext { | |
66 | sigset_t uc_sigmask; | |
67 | mcontext_t uc_mcontext; | |
68 | ... | |
69 | }; | |
70 | ||
71 | mcontext_t is defined as: | |
72 | ||
73 | struct { | |
74 | unsigned int __gregs[17]; | |
75 | size_t mc_vfp_size; | |
76 | void *mc_vfp_ptr; | |
77 | ... | |
78 | }; | |
79 | ||
80 | mcontext_vfp_t is defined as: | |
81 | ||
82 | struct { | |
83 | uint64_t mcv_reg[32]; | |
84 | uint32_t mcv_fpscr; | |
85 | }; | |
86 | ||
87 | If the VFP state is valid, then mc_vfp_ptr will point to sf_vfp in | |
88 | the sigframe, otherwise it is NULL. There is no non-VFP floating | |
89 | point register state saved in the signal frame. */ | |
90 | ||
7176dfd2 JB |
91 | #define ARM_SIGFRAME_UCONTEXT_OFFSET 64 |
92 | #define ARM_UCONTEXT_MCONTEXT_OFFSET 16 | |
93 | #define ARM_MCONTEXT_VFP_PTR_OFFSET 72 | |
94 | ||
95 | /* Implement the "init" method of struct tramp_frame. */ | |
96 | ||
97 | static void | |
98 | arm_fbsd_sigframe_init (const struct tramp_frame *self, | |
99 | struct frame_info *this_frame, | |
100 | struct trad_frame_cache *this_cache, | |
101 | CORE_ADDR func) | |
102 | { | |
103 | struct gdbarch *gdbarch = get_frame_arch (this_frame); | |
104 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | |
105 | CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); | |
106 | CORE_ADDR mcontext_addr = (sp | |
107 | + ARM_SIGFRAME_UCONTEXT_OFFSET | |
108 | + ARM_UCONTEXT_MCONTEXT_OFFSET); | |
109 | ULONGEST mcontext_vfp_addr; | |
110 | ||
7054e2ff JB |
111 | trad_frame_set_reg_regmap (this_cache, arm_fbsd_gregmap, mcontext_addr, |
112 | regcache_map_entry_size (arm_fbsd_gregmap)); | |
7176dfd2 JB |
113 | |
114 | if (safe_read_memory_unsigned_integer (mcontext_addr | |
115 | + ARM_MCONTEXT_VFP_PTR_OFFSET, 4, | |
116 | byte_order, | |
117 | &mcontext_vfp_addr) | |
118 | && mcontext_vfp_addr != 0) | |
7054e2ff JB |
119 | trad_frame_set_reg_regmap (this_cache, arm_fbsd_vfpregmap, mcontext_vfp_addr, |
120 | regcache_map_entry_size (arm_fbsd_vfpregmap)); | |
7176dfd2 JB |
121 | |
122 | trad_frame_set_id (this_cache, frame_id_build (sp, func)); | |
123 | } | |
124 | ||
125 | static const struct tramp_frame arm_fbsd_sigframe = | |
126 | { | |
127 | SIGTRAMP_FRAME, | |
128 | 4, | |
129 | { | |
7bc02706 TT |
130 | {0xe1a0000d, ULONGEST_MAX}, /* mov r0, sp */ |
131 | {0xe2800040, ULONGEST_MAX}, /* add r0, r0, #SIGF_UC */ | |
132 | {0xe59f700c, ULONGEST_MAX}, /* ldr r7, [pc, #12] */ | |
133 | {0xef0001a1, ULONGEST_MAX}, /* swi SYS_sigreturn */ | |
134 | {TRAMP_SENTINEL_INSN, ULONGEST_MAX} | |
7176dfd2 JB |
135 | }, |
136 | arm_fbsd_sigframe_init | |
137 | }; | |
138 | ||
7176dfd2 JB |
139 | /* Register set definitions. */ |
140 | ||
141 | const struct regset arm_fbsd_gregset = | |
142 | { | |
143 | arm_fbsd_gregmap, | |
144 | regcache_supply_regset, regcache_collect_regset | |
145 | }; | |
146 | ||
147 | const struct regset arm_fbsd_vfpregset = | |
148 | { | |
149 | arm_fbsd_vfpregmap, | |
150 | regcache_supply_regset, regcache_collect_regset | |
151 | }; | |
152 | ||
153 | /* Implement the "regset_from_core_section" gdbarch method. */ | |
154 | ||
155 | static void | |
156 | arm_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, | |
157 | iterate_over_regset_sections_cb *cb, | |
158 | void *cb_data, | |
159 | const struct regcache *regcache) | |
160 | { | |
161 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); | |
162 | ||
a616bb94 AH |
163 | cb (".reg", ARM_FBSD_SIZEOF_GREGSET, ARM_FBSD_SIZEOF_GREGSET, |
164 | &arm_fbsd_gregset, NULL, cb_data); | |
7176dfd2 JB |
165 | |
166 | /* While FreeBSD/arm cores do contain a NT_FPREGSET / ".reg2" | |
167 | register set, it is not populated with register values by the | |
168 | kernel but just contains all zeroes. */ | |
169 | if (tdep->vfp_register_count > 0) | |
a616bb94 AH |
170 | cb (".reg-arm-vfp", ARM_FBSD_SIZEOF_VFPREGSET, ARM_FBSD_SIZEOF_VFPREGSET, |
171 | &arm_fbsd_vfpregset, "VFP floating-point", cb_data); | |
7176dfd2 JB |
172 | } |
173 | ||
174 | /* Lookup a target description from a target's AT_HWCAP auxiliary | |
175 | vector. */ | |
176 | ||
177 | const struct target_desc * | |
178 | arm_fbsd_read_description_auxv (struct target_ops *target) | |
179 | { | |
180 | CORE_ADDR arm_hwcap = 0; | |
181 | ||
182 | if (target_auxv_search (target, AT_FREEBSD_HWCAP, &arm_hwcap) != 1) | |
d105cce5 | 183 | return nullptr; |
7176dfd2 JB |
184 | |
185 | if (arm_hwcap & HWCAP_VFP) | |
186 | { | |
187 | if (arm_hwcap & HWCAP_NEON) | |
d105cce5 | 188 | return aarch32_read_description (); |
7176dfd2 JB |
189 | else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPD32)) |
190 | == (HWCAP_VFPv3 | HWCAP_VFPD32)) | |
d105cce5 | 191 | return arm_read_description (ARM_FP_TYPE_VFPV3); |
7176dfd2 | 192 | else |
d105cce5 | 193 | return arm_read_description (ARM_FP_TYPE_VFPV2); |
7176dfd2 JB |
194 | } |
195 | ||
d105cce5 | 196 | return nullptr; |
7176dfd2 JB |
197 | } |
198 | ||
199 | /* Implement the "core_read_description" gdbarch method. */ | |
200 | ||
201 | static const struct target_desc * | |
202 | arm_fbsd_core_read_description (struct gdbarch *gdbarch, | |
203 | struct target_ops *target, | |
204 | bfd *abfd) | |
205 | { | |
206 | return arm_fbsd_read_description_auxv (target); | |
207 | } | |
208 | ||
209 | /* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ | |
210 | ||
211 | static void | |
212 | arm_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
213 | { | |
214 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); | |
215 | ||
216 | /* Generic FreeBSD support. */ | |
217 | fbsd_init_abi (info, gdbarch); | |
218 | ||
219 | if (tdep->fp_model == ARM_FLOAT_AUTO) | |
220 | tdep->fp_model = ARM_FLOAT_SOFT_VFP; | |
221 | ||
222 | tramp_frame_prepend_unwinder (gdbarch, &arm_fbsd_sigframe); | |
223 | ||
224 | set_solib_svr4_fetch_link_map_offsets | |
225 | (gdbarch, svr4_ilp32_fetch_link_map_offsets); | |
226 | ||
227 | tdep->jb_pc = 24; | |
228 | tdep->jb_elt_size = 4; | |
229 | ||
230 | set_gdbarch_iterate_over_regset_sections | |
231 | (gdbarch, arm_fbsd_iterate_over_regset_sections); | |
232 | set_gdbarch_core_read_description (gdbarch, arm_fbsd_core_read_description); | |
233 | ||
234 | /* Single stepping. */ | |
235 | set_gdbarch_software_single_step (gdbarch, arm_software_single_step); | |
236 | } | |
237 | ||
238 | void | |
239 | _initialize_arm_fbsd_tdep (void) | |
240 | { | |
241 | gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_FREEBSD, | |
242 | arm_fbsd_init_abi); | |
243 | } |