xref: /netbsd-src/external/gpl3/gdb/dist/gdbserver/linux-m68k-low.cc (revision f1c2b495c8d0ed769f039187bdd4f963026e012b)
18dffb485Schristos /* GNU/Linux/m68k specific low level interface, for the remote server for GDB.
2*f1c2b495Schristos    Copyright (C) 1995-2024 Free Software Foundation, Inc.
38dffb485Schristos 
48dffb485Schristos    This file is part of GDB.
58dffb485Schristos 
68dffb485Schristos    This program is free software; you can redistribute it and/or modify
78dffb485Schristos    it under the terms of the GNU General Public License as published by
88dffb485Schristos    the Free Software Foundation; either version 3 of the License, or
98dffb485Schristos    (at your option) any later version.
108dffb485Schristos 
118dffb485Schristos    This program is distributed in the hope that it will be useful,
128dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
138dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
148dffb485Schristos    GNU General Public License for more details.
158dffb485Schristos 
168dffb485Schristos    You should have received a copy of the GNU General Public License
178dffb485Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
188dffb485Schristos 
198dffb485Schristos #include "linux-low.h"
208dffb485Schristos 
218dffb485Schristos /* Linux target op definitions for the m68k architecture.  */
228dffb485Schristos 
238dffb485Schristos class m68k_target : public linux_process_target
248dffb485Schristos {
258dffb485Schristos public:
268dffb485Schristos 
278dffb485Schristos   const regs_info *get_regs_info () override;
288dffb485Schristos 
298dffb485Schristos   const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
308dffb485Schristos 
318dffb485Schristos protected:
328dffb485Schristos 
338dffb485Schristos   void low_arch_setup () override;
348dffb485Schristos 
358dffb485Schristos   bool low_cannot_fetch_register (int regno) override;
368dffb485Schristos 
378dffb485Schristos   bool low_cannot_store_register (int regno) override;
388dffb485Schristos 
398dffb485Schristos   bool low_supports_breakpoints () override;
408dffb485Schristos 
418dffb485Schristos   CORE_ADDR low_get_pc (regcache *regcache) override;
428dffb485Schristos 
438dffb485Schristos   void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
448dffb485Schristos 
458dffb485Schristos   int low_decr_pc_after_break () override;
468dffb485Schristos 
478dffb485Schristos   bool low_breakpoint_at (CORE_ADDR pc) override;
488dffb485Schristos };
498dffb485Schristos 
508dffb485Schristos /* The singleton target ops object.  */
518dffb485Schristos 
528dffb485Schristos static m68k_target the_m68k_target;
538dffb485Schristos 
548dffb485Schristos bool
558dffb485Schristos m68k_target::low_supports_breakpoints ()
568dffb485Schristos {
578dffb485Schristos   return true;
588dffb485Schristos }
598dffb485Schristos 
608dffb485Schristos CORE_ADDR
618dffb485Schristos m68k_target::low_get_pc (regcache *regcache)
628dffb485Schristos {
638dffb485Schristos   return linux_get_pc_32bit (regcache);
648dffb485Schristos }
658dffb485Schristos 
668dffb485Schristos void
678dffb485Schristos m68k_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
688dffb485Schristos {
698dffb485Schristos   linux_set_pc_32bit (regcache, pc);
708dffb485Schristos }
718dffb485Schristos 
728dffb485Schristos int
738dffb485Schristos m68k_target::low_decr_pc_after_break ()
748dffb485Schristos {
758dffb485Schristos   return 2;
768dffb485Schristos }
778dffb485Schristos 
788dffb485Schristos /* Defined in auto-generated file reg-m68k.c.  */
798dffb485Schristos void init_registers_m68k (void);
808dffb485Schristos extern const struct target_desc *tdesc_m68k;
818dffb485Schristos 
828dffb485Schristos #ifdef HAVE_SYS_REG_H
838dffb485Schristos #include <sys/reg.h>
848dffb485Schristos #endif
858dffb485Schristos 
868dffb485Schristos #define m68k_num_regs 29
878dffb485Schristos #define m68k_num_gregs 18
888dffb485Schristos 
898dffb485Schristos /* This table must line up with REGISTER_NAMES in tm-m68k.h */
908dffb485Schristos static int m68k_regmap[] =
918dffb485Schristos {
928dffb485Schristos #ifdef PT_D0
938dffb485Schristos   PT_D0 * 4, PT_D1 * 4, PT_D2 * 4, PT_D3 * 4,
948dffb485Schristos   PT_D4 * 4, PT_D5 * 4, PT_D6 * 4, PT_D7 * 4,
958dffb485Schristos   PT_A0 * 4, PT_A1 * 4, PT_A2 * 4, PT_A3 * 4,
968dffb485Schristos   PT_A4 * 4, PT_A5 * 4, PT_A6 * 4, PT_USP * 4,
978dffb485Schristos   PT_SR * 4, PT_PC * 4,
988dffb485Schristos #else
998dffb485Schristos   14 * 4, 0 * 4, 1 * 4, 2 * 4, 3 * 4, 4 * 4, 5 * 4, 6 * 4,
1008dffb485Schristos   7 * 4, 8 * 4, 9 * 4, 10 * 4, 11 * 4, 12 * 4, 13 * 4, 15 * 4,
1018dffb485Schristos   17 * 4, 18 * 4,
1028dffb485Schristos #endif
1038dffb485Schristos #ifdef PT_FP0
1048dffb485Schristos   PT_FP0 * 4, PT_FP1 * 4, PT_FP2 * 4, PT_FP3 * 4,
1058dffb485Schristos   PT_FP4 * 4, PT_FP5 * 4, PT_FP6 * 4, PT_FP7 * 4,
1068dffb485Schristos   PT_FPCR * 4, PT_FPSR * 4, PT_FPIAR * 4
1078dffb485Schristos #else
1088dffb485Schristos   21 * 4, 24 * 4, 27 * 4, 30 * 4, 33 * 4, 36 * 4,
1098dffb485Schristos   39 * 4, 42 * 4, 45 * 4, 46 * 4, 47 * 4
1108dffb485Schristos #endif
1118dffb485Schristos };
1128dffb485Schristos 
1138dffb485Schristos bool
1148dffb485Schristos m68k_target::low_cannot_store_register (int regno)
1158dffb485Schristos {
1168dffb485Schristos   return (regno >= m68k_num_regs);
1178dffb485Schristos }
1188dffb485Schristos 
1198dffb485Schristos bool
1208dffb485Schristos m68k_target::low_cannot_fetch_register (int regno)
1218dffb485Schristos {
1228dffb485Schristos   return (regno >= m68k_num_regs);
1238dffb485Schristos }
1248dffb485Schristos 
1258dffb485Schristos #ifdef HAVE_PTRACE_GETREGS
1268dffb485Schristos #include <sys/procfs.h>
1278dffb485Schristos #include "nat/gdb_ptrace.h"
1288dffb485Schristos 
1298dffb485Schristos static void
1308dffb485Schristos m68k_fill_gregset (struct regcache *regcache, void *buf)
1318dffb485Schristos {
1328dffb485Schristos   int i;
1338dffb485Schristos 
1348dffb485Schristos   for (i = 0; i < m68k_num_gregs; i++)
1358dffb485Schristos     collect_register (regcache, i, (char *) buf + m68k_regmap[i]);
1368dffb485Schristos }
1378dffb485Schristos 
1388dffb485Schristos static void
1398dffb485Schristos m68k_store_gregset (struct regcache *regcache, const void *buf)
1408dffb485Schristos {
1418dffb485Schristos   int i;
1428dffb485Schristos 
1438dffb485Schristos   for (i = 0; i < m68k_num_gregs; i++)
1448dffb485Schristos     supply_register (regcache, i, (const char *) buf + m68k_regmap[i]);
1458dffb485Schristos }
1468dffb485Schristos 
1478dffb485Schristos static void
1488dffb485Schristos m68k_fill_fpregset (struct regcache *regcache, void *buf)
1498dffb485Schristos {
1508dffb485Schristos   int i;
1518dffb485Schristos 
1528dffb485Schristos   for (i = m68k_num_gregs; i < m68k_num_regs; i++)
1538dffb485Schristos     collect_register (regcache, i, ((char *) buf
1548dffb485Schristos 			 + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs])));
1558dffb485Schristos }
1568dffb485Schristos 
1578dffb485Schristos static void
1588dffb485Schristos m68k_store_fpregset (struct regcache *regcache, const void *buf)
1598dffb485Schristos {
1608dffb485Schristos   int i;
1618dffb485Schristos 
1628dffb485Schristos   for (i = m68k_num_gregs; i < m68k_num_regs; i++)
1638dffb485Schristos     supply_register (regcache, i, ((const char *) buf
1648dffb485Schristos 			 + (m68k_regmap[i] - m68k_regmap[m68k_num_gregs])));
1658dffb485Schristos }
1668dffb485Schristos 
1678dffb485Schristos #endif /* HAVE_PTRACE_GETREGS */
1688dffb485Schristos 
1698dffb485Schristos static struct regset_info m68k_regsets[] = {
1708dffb485Schristos #ifdef HAVE_PTRACE_GETREGS
1718dffb485Schristos   { PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
1728dffb485Schristos     GENERAL_REGS,
1738dffb485Schristos     m68k_fill_gregset, m68k_store_gregset },
1748dffb485Schristos   { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t),
1758dffb485Schristos     FP_REGS,
1768dffb485Schristos     m68k_fill_fpregset, m68k_store_fpregset },
1778dffb485Schristos #endif /* HAVE_PTRACE_GETREGS */
1788dffb485Schristos   NULL_REGSET
1798dffb485Schristos };
1808dffb485Schristos 
1818dffb485Schristos static const gdb_byte m68k_breakpoint[] = { 0x4E, 0x4F };
1828dffb485Schristos #define m68k_breakpoint_len 2
1838dffb485Schristos 
1848dffb485Schristos /* Implementation of target ops method "sw_breakpoint_from_kind".  */
1858dffb485Schristos 
1868dffb485Schristos const gdb_byte *
1878dffb485Schristos m68k_target::sw_breakpoint_from_kind (int kind, int *size)
1888dffb485Schristos {
1898dffb485Schristos   *size = m68k_breakpoint_len;
1908dffb485Schristos   return m68k_breakpoint;
1918dffb485Schristos }
1928dffb485Schristos 
1938dffb485Schristos bool
1948dffb485Schristos m68k_target::low_breakpoint_at (CORE_ADDR pc)
1958dffb485Schristos {
1968dffb485Schristos   unsigned char c[2];
1978dffb485Schristos 
1988dffb485Schristos   read_inferior_memory (pc, c, 2);
1998dffb485Schristos   if (c[0] == 0x4E && c[1] == 0x4F)
2008dffb485Schristos     return true;
2018dffb485Schristos 
2028dffb485Schristos   return false;
2038dffb485Schristos }
2048dffb485Schristos 
2058dffb485Schristos #include <asm/ptrace.h>
2068dffb485Schristos 
2078dffb485Schristos #ifdef PTRACE_GET_THREAD_AREA
2088dffb485Schristos /* Fetch the thread-local storage pointer for libthread_db.  */
2098dffb485Schristos 
2108dffb485Schristos ps_err_e
2118dffb485Schristos ps_get_thread_area (struct ps_prochandle *ph,
2128dffb485Schristos 		    lwpid_t lwpid, int idx, void **base)
2138dffb485Schristos {
2148dffb485Schristos   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
2158dffb485Schristos     return PS_ERR;
2168dffb485Schristos 
2178dffb485Schristos   /* IDX is the bias from the thread pointer to the beginning of the
2188dffb485Schristos      thread descriptor.  It has to be subtracted due to implementation
2198dffb485Schristos      quirks in libthread_db.  */
2208dffb485Schristos   *base = (void *) ((char *)*base - idx);
2218dffb485Schristos 
2228dffb485Schristos   return PS_OK;
2238dffb485Schristos }
2248dffb485Schristos #endif /* PTRACE_GET_THREAD_AREA */
2258dffb485Schristos 
2268dffb485Schristos static struct regsets_info m68k_regsets_info =
2278dffb485Schristos   {
2288dffb485Schristos     m68k_regsets, /* regsets */
2298dffb485Schristos     0, /* num_regsets */
2308dffb485Schristos     NULL, /* disabled_regsets */
2318dffb485Schristos   };
2328dffb485Schristos 
2338dffb485Schristos static struct usrregs_info m68k_usrregs_info =
2348dffb485Schristos   {
2358dffb485Schristos     m68k_num_regs,
2368dffb485Schristos     m68k_regmap,
2378dffb485Schristos   };
2388dffb485Schristos 
2398dffb485Schristos static struct regs_info myregs_info =
2408dffb485Schristos   {
2418dffb485Schristos     NULL, /* regset_bitmap */
2428dffb485Schristos     &m68k_usrregs_info,
2438dffb485Schristos     &m68k_regsets_info
2448dffb485Schristos   };
2458dffb485Schristos 
2468dffb485Schristos const regs_info *
2478dffb485Schristos m68k_target::get_regs_info ()
2488dffb485Schristos {
2498dffb485Schristos   return &myregs_info;
2508dffb485Schristos }
2518dffb485Schristos 
2528dffb485Schristos void
2538dffb485Schristos m68k_target::low_arch_setup ()
2548dffb485Schristos {
2558dffb485Schristos   current_process ()->tdesc = tdesc_m68k;
2568dffb485Schristos }
2578dffb485Schristos 
2588dffb485Schristos /* The linux target ops object.  */
2598dffb485Schristos 
2608dffb485Schristos linux_process_target *the_linux_target = &the_m68k_target;
2618dffb485Schristos 
2628dffb485Schristos void
2638dffb485Schristos initialize_low_arch (void)
2648dffb485Schristos {
2658dffb485Schristos   /* Initialize the Linux target descriptions.  */
2668dffb485Schristos   init_registers_m68k ();
2678dffb485Schristos 
2688dffb485Schristos   initialize_regsets_info (&m68k_regsets_info);
2698dffb485Schristos }
270