Commit | Line | Data |
---|---|---|
8d7f0635 AK |
1 | /* Target dependent code for GNU/Linux ARC. |
2 | ||
3 | Copyright 2020 Free Software Foundation, Inc. | |
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 | /* GDB header files. */ | |
21 | #include "defs.h" | |
22 | #include "linux-tdep.h" | |
23 | #include "objfiles.h" | |
24 | #include "opcode/arc.h" | |
25 | #include "osabi.h" | |
26 | #include "solib-svr4.h" | |
27 | ||
28 | /* ARC header files. */ | |
29 | #include "opcodes/arc-dis.h" | |
30 | #include "arc-tdep.h" | |
31 | ||
32 | /* Implement the "cannot_fetch_register" gdbarch method. */ | |
33 | ||
34 | static int | |
35 | arc_linux_cannot_fetch_register (struct gdbarch *gdbarch, int regnum) | |
36 | { | |
37 | /* Assume that register is readable if it is unknown. */ | |
38 | switch (regnum) | |
39 | { | |
40 | case ARC_ILINK_REGNUM: | |
41 | case ARC_RESERVED_REGNUM: | |
42 | case ARC_LIMM_REGNUM: | |
43 | return true; | |
44 | case ARC_R30_REGNUM: | |
45 | case ARC_R58_REGNUM: | |
46 | case ARC_R59_REGNUM: | |
47 | return !arc_mach_is_arcv2 (gdbarch); | |
48 | } | |
49 | return (regnum > ARC_BLINK_REGNUM) && (regnum < ARC_LP_COUNT_REGNUM); | |
50 | } | |
51 | ||
52 | /* Implement the "cannot_store_register" gdbarch method. */ | |
53 | ||
54 | static int | |
55 | arc_linux_cannot_store_register (struct gdbarch *gdbarch, int regnum) | |
56 | { | |
57 | /* Assume that register is writable if it is unknown. */ | |
58 | switch (regnum) | |
59 | { | |
60 | case ARC_ILINK_REGNUM: | |
61 | case ARC_RESERVED_REGNUM: | |
62 | case ARC_LIMM_REGNUM: | |
63 | case ARC_PCL_REGNUM: | |
64 | return true; | |
65 | case ARC_R30_REGNUM: | |
66 | case ARC_R58_REGNUM: | |
67 | case ARC_R59_REGNUM: | |
68 | return !arc_mach_is_arcv2 (gdbarch); | |
69 | } | |
70 | return (regnum > ARC_BLINK_REGNUM) && (regnum < ARC_LP_COUNT_REGNUM); | |
71 | } | |
72 | ||
73 | /* For ARC Linux, breakpoints use the 16-bit TRAP_S 1 instruction, which | |
74 | is 0x3e78 (little endian) or 0x783e (big endian). */ | |
75 | ||
76 | static const gdb_byte arc_linux_trap_s_be[] = { 0x78, 0x3e }; | |
77 | static const gdb_byte arc_linux_trap_s_le[] = { 0x3e, 0x78 }; | |
78 | static const int trap_size = 2; /* Number of bytes to insert "trap". */ | |
79 | ||
80 | /* Implement the "breakpoint_kind_from_pc" gdbarch method. */ | |
81 | ||
82 | static int | |
83 | arc_linux_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) | |
84 | { | |
85 | return trap_size; | |
86 | } | |
87 | ||
88 | /* Implement the "sw_breakpoint_from_kind" gdbarch method. */ | |
89 | ||
90 | static const gdb_byte * | |
91 | arc_linux_sw_breakpoint_from_kind (struct gdbarch *gdbarch, | |
92 | int kind, int *size) | |
93 | { | |
94 | *size = kind; | |
95 | return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) | |
96 | ? arc_linux_trap_s_be | |
97 | : arc_linux_trap_s_le); | |
98 | } | |
99 | ||
100 | /* Implement the "software_single_step" gdbarch method. */ | |
101 | ||
102 | static std::vector<CORE_ADDR> | |
103 | arc_linux_software_single_step (struct regcache *regcache) | |
104 | { | |
105 | struct gdbarch *gdbarch = regcache->arch (); | |
106 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); | |
107 | struct disassemble_info di = arc_disassemble_info (gdbarch); | |
108 | ||
109 | /* Read current instruction. */ | |
110 | struct arc_instruction curr_insn; | |
111 | arc_insn_decode (regcache_read_pc (regcache), &di, arc_delayed_print_insn, | |
112 | &curr_insn); | |
113 | CORE_ADDR next_pc = arc_insn_get_linear_next_pc (curr_insn); | |
114 | ||
115 | std::vector<CORE_ADDR> next_pcs; | |
116 | ||
117 | /* For instructions with delay slots, the fall thru is not the | |
118 | instruction immediately after the current instruction, but the one | |
119 | after that. */ | |
120 | if (curr_insn.has_delay_slot) | |
121 | { | |
122 | struct arc_instruction next_insn; | |
123 | arc_insn_decode (next_pc, &di, arc_delayed_print_insn, &next_insn); | |
124 | next_pcs.push_back (arc_insn_get_linear_next_pc (next_insn)); | |
125 | } | |
126 | else | |
127 | next_pcs.push_back (next_pc); | |
128 | ||
129 | ULONGEST status32; | |
130 | regcache_cooked_read_unsigned (regcache, gdbarch_ps_regnum (gdbarch), | |
131 | &status32); | |
132 | ||
133 | if (curr_insn.is_control_flow) | |
134 | { | |
135 | CORE_ADDR branch_pc = arc_insn_get_branch_target (curr_insn); | |
136 | if (branch_pc != next_pc) | |
137 | next_pcs.push_back (branch_pc); | |
138 | } | |
139 | /* Is current instruction the last in a loop body? */ | |
140 | else if (tdep->has_hw_loops) | |
141 | { | |
142 | /* If STATUS32.L is 1, then ZD-loops are disabled. */ | |
143 | if ((status32 & ARC_STATUS32_L_MASK) == 0) | |
144 | { | |
145 | ULONGEST lp_end, lp_start, lp_count; | |
146 | regcache_cooked_read_unsigned (regcache, ARC_LP_START_REGNUM, | |
147 | &lp_start); | |
148 | regcache_cooked_read_unsigned (regcache, ARC_LP_END_REGNUM, &lp_end); | |
149 | regcache_cooked_read_unsigned (regcache, ARC_LP_COUNT_REGNUM, | |
150 | &lp_count); | |
151 | ||
152 | if (arc_debug) | |
153 | { | |
154 | debug_printf ("arc-linux: lp_start = %s, lp_end = %s, " | |
155 | "lp_count = %s, next_pc = %s\n", | |
156 | paddress (gdbarch, lp_start), | |
157 | paddress (gdbarch, lp_end), | |
158 | pulongest (lp_count), | |
159 | paddress (gdbarch, next_pc)); | |
160 | } | |
161 | ||
162 | if (next_pc == lp_end && lp_count > 1) | |
163 | { | |
164 | /* The instruction is in effect a jump back to the start of | |
165 | the loop. */ | |
166 | next_pcs.push_back (lp_start); | |
167 | } | |
168 | } | |
169 | } | |
170 | ||
171 | /* Is this a delay slot? Then next PC is in BTA register. */ | |
172 | if ((status32 & ARC_STATUS32_DE_MASK) != 0) | |
173 | { | |
174 | ULONGEST bta; | |
175 | regcache_cooked_read_unsigned (regcache, ARC_BTA_REGNUM, &bta); | |
176 | next_pcs.push_back (bta); | |
177 | } | |
178 | ||
179 | return next_pcs; | |
180 | } | |
181 | ||
182 | /* Implement the "skip_solib_resolver" gdbarch method. | |
183 | ||
184 | See glibc_skip_solib_resolver for details. */ | |
185 | ||
186 | static CORE_ADDR | |
187 | arc_linux_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) | |
188 | { | |
189 | /* For uClibc 0.9.26+. | |
190 | ||
191 | An unresolved PLT entry points to "__dl_linux_resolve", which calls | |
192 | "_dl_linux_resolver" to do the resolving and then eventually jumps to | |
193 | the function. | |
194 | ||
195 | So we look for the symbol `_dl_linux_resolver', and if we are there, | |
196 | gdb sets a breakpoint at the return address, and continues. */ | |
197 | struct bound_minimal_symbol resolver | |
198 | = lookup_minimal_symbol ("_dl_linux_resolver", NULL, NULL); | |
199 | ||
200 | if (arc_debug) | |
201 | { | |
202 | if (resolver.minsym != nullptr) | |
203 | { | |
204 | CORE_ADDR res_addr = BMSYMBOL_VALUE_ADDRESS (resolver); | |
205 | debug_printf ("arc-linux: skip_solib_resolver (): " | |
206 | "pc = %s, resolver at %s\n", | |
207 | print_core_address (gdbarch, pc), | |
208 | print_core_address (gdbarch, res_addr)); | |
209 | } | |
210 | else | |
211 | { | |
212 | debug_printf ("arc-linux: skip_solib_resolver (): " | |
213 | "pc = %s, no resolver found\n", | |
214 | print_core_address (gdbarch, pc)); | |
215 | } | |
216 | } | |
217 | ||
218 | if (resolver.minsym != nullptr && BMSYMBOL_VALUE_ADDRESS (resolver) == pc) | |
219 | { | |
220 | /* Find the return address. */ | |
221 | return frame_unwind_caller_pc (get_current_frame ()); | |
222 | } | |
223 | else | |
224 | { | |
225 | /* No breakpoint required. */ | |
226 | return 0; | |
227 | } | |
228 | } | |
229 | ||
230 | /* Initialization specific to Linux environment. */ | |
231 | ||
232 | static void | |
233 | arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
234 | { | |
235 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); | |
236 | ||
237 | if (arc_debug) | |
238 | debug_printf ("arc-linux: GNU/Linux OS/ABI initialization.\n"); | |
239 | ||
240 | /* If we are using Linux, we have in uClibc | |
241 | (libc/sysdeps/linux/arc/bits/setjmp.h): | |
242 | ||
243 | typedef int __jmp_buf[13+1+1+1]; //r13-r25, fp, sp, blink | |
244 | ||
245 | Where "blink" is a stored PC of a caller function. | |
246 | */ | |
247 | tdep->jb_pc = 15; | |
248 | ||
249 | linux_init_abi (info, gdbarch); | |
250 | ||
251 | /* Set up target dependent GDB architecture entries. */ | |
252 | set_gdbarch_cannot_fetch_register (gdbarch, arc_linux_cannot_fetch_register); | |
253 | set_gdbarch_cannot_store_register (gdbarch, arc_linux_cannot_store_register); | |
254 | set_gdbarch_breakpoint_kind_from_pc (gdbarch, | |
255 | arc_linux_breakpoint_kind_from_pc); | |
256 | set_gdbarch_sw_breakpoint_from_kind (gdbarch, | |
257 | arc_linux_sw_breakpoint_from_kind); | |
258 | set_gdbarch_fetch_tls_load_module_address (gdbarch, | |
259 | svr4_fetch_objfile_link_map); | |
260 | set_gdbarch_software_single_step (gdbarch, arc_linux_software_single_step); | |
261 | set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); | |
262 | set_gdbarch_skip_solib_resolver (gdbarch, arc_linux_skip_solib_resolver); | |
263 | ||
264 | /* GNU/Linux uses SVR4-style shared libraries, with 32-bit ints, longs | |
265 | and pointers (ILP32). */ | |
266 | set_solib_svr4_fetch_link_map_offsets (gdbarch, | |
267 | svr4_ilp32_fetch_link_map_offsets); | |
268 | } | |
269 | ||
270 | /* Suppress warning from -Wmissing-prototypes. */ | |
271 | extern initialize_file_ftype _initialize_arc_linux_tdep; | |
272 | ||
273 | void | |
274 | _initialize_arc_linux_tdep () | |
275 | { | |
276 | gdbarch_register_osabi (bfd_arch_arc, 0, GDB_OSABI_LINUX, | |
277 | arc_linux_init_osabi); | |
278 | } |