1/* Target-dependent code for GNU/Linux Super-H.
2
3   Copyright (C) 2005-2023 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#include "defs.h"
21#include "osabi.h"
22
23#include "solib-svr4.h"
24#include "symtab.h"
25
26#include "trad-frame.h"
27#include "tramp-frame.h"
28
29#include "glibc-tdep.h"
30#include "sh-tdep.h"
31#include "linux-tdep.h"
32#include "gdbarch.h"
33
34#define REGSx16(base) \
35  {(base),      0}, \
36  {(base) +  1, 4}, \
37  {(base) +  2, 8}, \
38  {(base) +  3, 12}, \
39  {(base) +  4, 16}, \
40  {(base) +  5, 20}, \
41  {(base) +  6, 24}, \
42  {(base) +  7, 28}, \
43  {(base) +  8, 32}, \
44  {(base) +  9, 36}, \
45  {(base) + 10, 40}, \
46  {(base) + 11, 44}, \
47  {(base) + 12, 48}, \
48  {(base) + 13, 52}, \
49  {(base) + 14, 56}, \
50  {(base) + 15, 60}
51
52/* Describe the contents of the .reg section of the core file.  */
53
54static const struct sh_corefile_regmap gregs_table[] =
55{
56  REGSx16 (R0_REGNUM),
57  {PC_REGNUM,   64},
58  {PR_REGNUM,   68},
59  {SR_REGNUM,   72},
60  {GBR_REGNUM,  76},
61  {MACH_REGNUM, 80},
62  {MACL_REGNUM, 84},
63  {-1 /* Terminator.  */, 0}
64};
65
66/* Describe the contents of the .reg2 section of the core file.  */
67
68static const struct sh_corefile_regmap fpregs_table[] =
69{
70  REGSx16 (FR0_REGNUM),
71  /* REGSx16 xfp_regs omitted.  */
72  {FPSCR_REGNUM, 128},
73  {FPUL_REGNUM,  132},
74  {-1 /* Terminator.  */, 0}
75};
76
77/* SH signal handler frame support.  */
78
79static void
80sh_linux_sigtramp_cache (frame_info_ptr this_frame,
81			 struct trad_frame_cache *this_cache,
82			 CORE_ADDR func, int regs_offset)
83{
84  int i;
85  struct gdbarch *gdbarch = get_frame_arch (this_frame);
86  CORE_ADDR base = get_frame_register_unsigned (this_frame,
87						gdbarch_sp_regnum (gdbarch));
88  CORE_ADDR regs = base + regs_offset;
89
90  for (i = 0; i < 18; i++)
91    trad_frame_set_reg_addr (this_cache, i, regs + i * 4);
92
93  trad_frame_set_reg_addr (this_cache, SR_REGNUM, regs + 18 * 4);
94  trad_frame_set_reg_addr (this_cache, GBR_REGNUM, regs + 19 * 4);
95  trad_frame_set_reg_addr (this_cache, MACH_REGNUM, regs + 20 * 4);
96  trad_frame_set_reg_addr (this_cache, MACL_REGNUM, regs + 21 * 4);
97
98  /* Restore FP state if we have an FPU.  */
99  if (gdbarch_fp0_regnum (gdbarch) != -1)
100    {
101      CORE_ADDR fpregs = regs + 22 * 4;
102      for (i = FR0_REGNUM; i <= FP_LAST_REGNUM; i++)
103	trad_frame_set_reg_addr (this_cache, i, fpregs + i * 4);
104      trad_frame_set_reg_addr (this_cache, FPSCR_REGNUM, fpregs + 32 * 4);
105      trad_frame_set_reg_addr (this_cache, FPUL_REGNUM, fpregs + 33 * 4);
106    }
107
108  /* Save a frame ID.  */
109  trad_frame_set_id (this_cache, frame_id_build (base, func));
110}
111
112/* Implement struct tramp_frame "init" callbacks for signal
113   trampolines on 32-bit SH.  */
114
115static void
116sh_linux_sigreturn_init (const struct tramp_frame *self,
117			 frame_info_ptr this_frame,
118			 struct trad_frame_cache *this_cache,
119			 CORE_ADDR func)
120{
121  /* SH 32-bit sigframe: sigcontext at start of sigframe,
122     registers start after a single 'oldmask' word.  */
123  sh_linux_sigtramp_cache (this_frame, this_cache, func, 4);
124}
125
126static void
127sh_linux_rt_sigreturn_init (const struct tramp_frame *self,
128			    frame_info_ptr this_frame,
129			    struct trad_frame_cache *this_cache,
130			    CORE_ADDR func)
131{
132  /* SH 32-bit rt_sigframe: starts with a siginfo (128 bytes), then
133     we can find sigcontext embedded within a ucontext (offset 20 bytes).
134     Then registers start after a single 'oldmask' word.  */
135  sh_linux_sigtramp_cache (this_frame, this_cache, func,
136			   128 /* sizeof (struct siginfo)  */
137			   + 20 /* offsetof (struct ucontext, uc_mcontext) */
138			   + 4 /* oldmask word at start of sigcontext */);
139}
140
141/* Instruction patterns.  */
142#define SH_MOVW     0x9305
143#define SH_TRAP     0xc300
144#define SH_OR_R0_R0 0x200b
145
146/* SH sigreturn syscall numbers.  */
147#define SH_NR_SIGRETURN 0x0077
148#define SH_NR_RT_SIGRETURN 0x00ad
149
150static struct tramp_frame sh_linux_sigreturn_tramp_frame = {
151  SIGTRAMP_FRAME,
152  2,
153  {
154    { SH_MOVW, 0xffff },
155    { SH_TRAP, 0xff00 }, /* #imm argument part filtered out.  */
156    { SH_OR_R0_R0, 0xffff },
157    { SH_OR_R0_R0, 0xffff },
158    { SH_OR_R0_R0, 0xffff },
159    { SH_OR_R0_R0, 0xffff },
160    { SH_OR_R0_R0, 0xffff },
161    { SH_NR_SIGRETURN, 0xffff },
162    { TRAMP_SENTINEL_INSN }
163  },
164  sh_linux_sigreturn_init
165};
166
167static struct tramp_frame sh_linux_rt_sigreturn_tramp_frame = {
168  SIGTRAMP_FRAME,
169  2,
170  {
171    { SH_MOVW, 0xffff },
172    { SH_TRAP, 0xff00 }, /* #imm argument part filtered out.  */
173    { SH_OR_R0_R0, 0xffff },
174    { SH_OR_R0_R0, 0xffff },
175    { SH_OR_R0_R0, 0xffff },
176    { SH_OR_R0_R0, 0xffff },
177    { SH_OR_R0_R0, 0xffff },
178    { SH_NR_RT_SIGRETURN, 0xffff },
179    { TRAMP_SENTINEL_INSN }
180  },
181  sh_linux_rt_sigreturn_init
182};
183
184static void
185sh_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
186{
187  linux_init_abi (info, gdbarch, 0);
188
189  /* GNU/Linux uses SVR4-style shared libraries.  */
190  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
191  set_solib_svr4_fetch_link_map_offsets
192    (gdbarch, linux_ilp32_fetch_link_map_offsets);
193  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
194
195  set_gdbarch_fetch_tls_load_module_address (gdbarch,
196					     svr4_fetch_objfile_link_map);
197
198  sh_gdbarch_tdep *tdep = gdbarch_tdep<sh_gdbarch_tdep> (gdbarch);
199
200  /* Remember regset characteristics.  The sizes should match
201     elf_gregset_t and elf_fpregset_t from Linux.  */
202  tdep->core_gregmap = (struct sh_corefile_regmap *) gregs_table;
203  tdep->sizeof_gregset = 92;
204  tdep->core_fpregmap = (struct sh_corefile_regmap *) fpregs_table;
205  tdep->sizeof_fpregset = 136;
206
207  tramp_frame_prepend_unwinder (gdbarch, &sh_linux_sigreturn_tramp_frame);
208  tramp_frame_prepend_unwinder (gdbarch, &sh_linux_rt_sigreturn_tramp_frame);
209}
210
211void _initialize_sh_linux_tdep ();
212void
213_initialize_sh_linux_tdep ()
214{
215  gdbarch_register_osabi (bfd_arch_sh, 0, GDB_OSABI_LINUX, sh_linux_init_abi);
216}
217