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