1 /* GNU/Linux/m68k specific low level interface, for the remote server for GDB. 2 Copyright (C) 1995-2024 Free Software Foundation, Inc. 3 4 This file is part of GDB. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #include "linux-low.h" 20 21 /* Linux target op definitions for the m68k architecture. */ 22 23 class m68k_target : public linux_process_target 24 { 25 public: 26 27 const regs_info *get_regs_info () override; 28 29 const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override; 30 31 protected: 32 33 void low_arch_setup () override; 34 35 bool low_cannot_fetch_register (int regno) override; 36 37 bool low_cannot_store_register (int regno) override; 38 39 bool low_supports_breakpoints () override; 40 41 CORE_ADDR low_get_pc (regcache *regcache) override; 42 43 void low_set_pc (regcache *regcache, CORE_ADDR newpc) override; 44 45 int low_decr_pc_after_break () override; 46 47 bool low_breakpoint_at (CORE_ADDR pc) override; 48 }; 49 50 /* The singleton target ops object. */ 51 52 static m68k_target the_m68k_target; 53 54 bool 55 m68k_target::low_supports_breakpoints () 56 { 57 return true; 58 } 59 60 CORE_ADDR 61 m68k_target::low_get_pc (regcache *regcache) 62 { 63 return linux_get_pc_32bit (regcache); 64 } 65 66 void 67 m68k_target::low_set_pc (regcache *regcache, CORE_ADDR pc) 68 { 69 linux_set_pc_32bit (regcache, pc); 70 } 71 72 int 73 m68k_target::low_decr_pc_after_break () 74 { 75 return 2; 76 } 77 78 /* Defined in auto-generated file reg-m68k.c. */ 79 void init_registers_m68k (void); 80 extern const struct target_desc *tdesc_m68k; 81 82 #ifdef HAVE_SYS_REG_H 83 #include <sys/reg.h> 84 #endif 85 86 #define m68k_num_regs 29 87 #define m68k_num_gregs 18 88 89 /* This table must line up with REGISTER_NAMES in tm-m68k.h */ 90 static int m68k_regmap[] = 91 { 92 #ifdef PT_D0 93 PT_D0 * 4, PT_D1 * 4, PT_D2 * 4, PT_D3 * 4, 94 PT_D4 * 4, PT_D5 * 4, PT_D6 * 4, PT_D7 * 4, 95 PT_A0 * 4, PT_A1 * 4, PT_A2 * 4, PT_A3 * 4, 96 PT_A4 * 4, PT_A5 * 4, PT_A6 * 4, PT_USP * 4, 97 PT_SR * 4, PT_PC * 4, 98 #else 99 14 * 4, 0 * 4, 1 * 4, 2 * 4, 3 * 4, 4 * 4, 5 * 4, 6 * 4, 100 7 * 4, 8 * 4, 9 * 4, 10 * 4, 11 * 4, 12 * 4, 13 * 4, 15 * 4, 101 17 * 4, 18 * 4, 102 #endif 103 #ifdef PT_FP0 104 PT_FP0 * 4, PT_FP1 * 4, PT_FP2 * 4, PT_FP3 * 4, 105 PT_FP4 * 4, PT_FP5 * 4, PT_FP6 * 4, PT_FP7 * 4, 106 PT_FPCR * 4, PT_FPSR * 4, PT_FPIAR * 4 107 #else 108 21 * 4, 24 * 4, 27 * 4, 30 * 4, 33 * 4, 36 * 4, 109 39 * 4, 42 * 4, 45 * 4, 46 * 4, 47 * 4 110 #endif 111 }; 112 113 bool 114 m68k_target::low_cannot_store_register (int regno) 115 { 116 return (regno >= m68k_num_regs); 117 } 118 119 bool 120 m68k_target::low_cannot_fetch_register (int regno) 121 { 122 return (regno >= m68k_num_regs); 123 } 124 125 #ifdef HAVE_PTRACE_GETREGS 126 #include <sys/procfs.h> 127 #include "nat/gdb_ptrace.h" 128 129 static void 130 m68k_fill_gregset (struct regcache *regcache, void *buf) 131 { 132 int i; 133 134 for (i = 0; i < m68k_num_gregs; i++) 135 collect_register (regcache, i, (char *) buf + m68k_regmap[i]); 136 } 137 138 static void 139 m68k_store_gregset (struct regcache *regcache, const void *buf) 140 { 141 int i; 142 143 for (i = 0; i < m68k_num_gregs; i++) 144 supply_register (regcache, i, (const char *) buf + m68k_regmap[i]); 145 } 146 147 static void 148 m68k_fill_fpregset (struct regcache *regcache, void *buf) 149 { 150 int i; 151 152 for (i = m68k_num_gregs; i < m68k_num_regs; i++) 153 collect_register (regcache, i, ((char *) buf 154 + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs]))); 155 } 156 157 static void 158 m68k_store_fpregset (struct regcache *regcache, const void *buf) 159 { 160 int i; 161 162 for (i = m68k_num_gregs; i < m68k_num_regs; i++) 163 supply_register (regcache, i, ((const char *) buf 164 + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs]))); 165 } 166 167 #endif /* HAVE_PTRACE_GETREGS */ 168 169 static struct regset_info m68k_regsets[] = { 170 #ifdef HAVE_PTRACE_GETREGS 171 { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t), 172 GENERAL_REGS, 173 m68k_fill_gregset, m68k_store_gregset }, 174 { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t), 175 FP_REGS, 176 m68k_fill_fpregset, m68k_store_fpregset }, 177 #endif /* HAVE_PTRACE_GETREGS */ 178 NULL_REGSET 179 }; 180 181 static const gdb_byte m68k_breakpoint[] = { 0x4E, 0x4F }; 182 #define m68k_breakpoint_len 2 183 184 /* Implementation of target ops method "sw_breakpoint_from_kind". */ 185 186 const gdb_byte * 187 m68k_target::sw_breakpoint_from_kind (int kind, int *size) 188 { 189 *size = m68k_breakpoint_len; 190 return m68k_breakpoint; 191 } 192 193 bool 194 m68k_target::low_breakpoint_at (CORE_ADDR pc) 195 { 196 unsigned char c[2]; 197 198 read_inferior_memory (pc, c, 2); 199 if (c[0] == 0x4E && c[1] == 0x4F) 200 return true; 201 202 return false; 203 } 204 205 #include <asm/ptrace.h> 206 207 #ifdef PTRACE_GET_THREAD_AREA 208 /* Fetch the thread-local storage pointer for libthread_db. */ 209 210 ps_err_e 211 ps_get_thread_area (struct ps_prochandle *ph, 212 lwpid_t lwpid, int idx, void **base) 213 { 214 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) 215 return PS_ERR; 216 217 /* IDX is the bias from the thread pointer to the beginning of the 218 thread descriptor. It has to be subtracted due to implementation 219 quirks in libthread_db. */ 220 *base = (void *) ((char *)*base - idx); 221 222 return PS_OK; 223 } 224 #endif /* PTRACE_GET_THREAD_AREA */ 225 226 static struct regsets_info m68k_regsets_info = 227 { 228 m68k_regsets, /* regsets */ 229 0, /* num_regsets */ 230 NULL, /* disabled_regsets */ 231 }; 232 233 static struct usrregs_info m68k_usrregs_info = 234 { 235 m68k_num_regs, 236 m68k_regmap, 237 }; 238 239 static struct regs_info myregs_info = 240 { 241 NULL, /* regset_bitmap */ 242 &m68k_usrregs_info, 243 &m68k_regsets_info 244 }; 245 246 const regs_info * 247 m68k_target::get_regs_info () 248 { 249 return &myregs_info; 250 } 251 252 void 253 m68k_target::low_arch_setup () 254 { 255 current_process ()->tdesc = tdesc_m68k; 256 } 257 258 /* The linux target ops object. */ 259 260 linux_process_target *the_linux_target = &the_m68k_target; 261 262 void 263 initialize_low_arch (void) 264 { 265 /* Initialize the Linux target descriptions. */ 266 init_registers_m68k (); 267 268 initialize_regsets_info (&m68k_regsets_info); 269 } 270