]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/sparc64-linux-tdep.c
Re: LoongArch: gas: Adjust DWARF CIE alignment factors
[thirdparty/binutils-gdb.git] / gdb / sparc64-linux-tdep.c
CommitLineData
386c036b
MK
1/* Target-dependent code for GNU/Linux UltraSPARC.
2
1d506c26 3 Copyright (C) 2003-2024 Free Software Foundation, Inc.
386c036b
MK
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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
386c036b
MK
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
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
386c036b 19
ec452525 20#include "extract-store-integer.h"
78a0fd57
DM
21#include "frame.h"
22#include "frame-unwind.h"
82ca8957 23#include "dwarf2/frame.h"
07c5f590 24#include "regset.h"
0b4294d3 25#include "regcache.h"
386c036b 26#include "gdbarch.h"
0b4294d3 27#include "gdbcore.h"
386c036b 28#include "osabi.h"
b2756930 29#include "solib-svr4.h"
78a0fd57
DM
30#include "symtab.h"
31#include "trad-frame.h"
70f1dc74 32#include "tramp-frame.h"
09de9781 33#include "xml-syscall.h"
a5ee0f0c 34#include "linux-tdep.h"
09de9781 35
58afddc6
WP
36/* ADI specific si_code */
37#ifndef SEGV_ACCADI
38#define SEGV_ACCADI 3
39#endif
40#ifndef SEGV_ADIDERR
41#define SEGV_ADIDERR 4
42#endif
43#ifndef SEGV_ADIPERR
44#define SEGV_ADIPERR 5
45#endif
46
09de9781
DM
47/* The syscall's XML filename for sparc 64-bit. */
48#define XML_SYSCALL_FILENAME_SPARC64 "syscalls/sparc64-linux.xml"
78a0fd57 49
386c036b
MK
50#include "sparc64-tdep.h"
51
70f1dc74 52/* Signal trampoline support. */
78a0fd57 53
81f726ab 54static void sparc64_linux_sigframe_init (const struct tramp_frame *self,
8480a37e 55 const frame_info_ptr &this_frame,
81f726ab
DM
56 struct trad_frame_cache *this_cache,
57 CORE_ADDR func);
78a0fd57 58
70f1dc74
MK
59/* See sparc-linux-tdep.c for details. Note that 64-bit binaries only
60 use RT signals. */
61
62static const struct tramp_frame sparc64_linux_rt_sigframe =
63{
81f726ab
DM
64 SIGTRAMP_FRAME,
65 4,
66 {
7bc02706
TT
67 { 0x82102065, ULONGEST_MAX }, /* mov __NR_rt_sigreturn, %g1 */
68 { 0x91d0206d, ULONGEST_MAX }, /* ta 0x6d */
69 { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
81f726ab
DM
70 },
71 sparc64_linux_sigframe_init
72};
78a0fd57 73
81f726ab
DM
74static void
75sparc64_linux_sigframe_init (const struct tramp_frame *self,
8480a37e 76 const frame_info_ptr &this_frame,
81f726ab
DM
77 struct trad_frame_cache *this_cache,
78 CORE_ADDR func)
78a0fd57 79{
80f9e3aa 80 CORE_ADDR base, addr, sp_addr;
78a0fd57
DM
81 int regnum;
82
5366653e 83 base = get_frame_register_unsigned (this_frame, SPARC_O1_REGNUM);
81f726ab 84 base += 128;
78a0fd57 85
70f1dc74 86 /* Offsets from <bits/sigcontext.h>. */
78a0fd57
DM
87
88 /* Since %g0 is always zero, keep the identity encoding. */
70f1dc74 89 addr = base + 8;
80f9e3aa 90 sp_addr = base + ((SPARC_SP_REGNUM - SPARC_G0_REGNUM) * 8);
81f726ab
DM
91 for (regnum = SPARC_G1_REGNUM; regnum <= SPARC_O7_REGNUM; regnum++)
92 {
93 trad_frame_set_reg_addr (this_cache, regnum, addr);
94 addr += 8;
95 }
78a0fd57 96
70f1dc74
MK
97 trad_frame_set_reg_addr (this_cache, SPARC64_STATE_REGNUM, addr + 0);
98 trad_frame_set_reg_addr (this_cache, SPARC64_PC_REGNUM, addr + 8);
99 trad_frame_set_reg_addr (this_cache, SPARC64_NPC_REGNUM, addr + 16);
100 trad_frame_set_reg_addr (this_cache, SPARC64_Y_REGNUM, addr + 24);
101 trad_frame_set_reg_addr (this_cache, SPARC64_FPRS_REGNUM, addr + 28);
78a0fd57 102
5366653e 103 base = get_frame_register_unsigned (this_frame, SPARC_SP_REGNUM);
80f9e3aa
DM
104 if (base & 1)
105 base += BIAS;
106
5366653e 107 addr = get_frame_memory_unsigned (this_frame, sp_addr, 8);
81f726ab
DM
108 if (addr & 1)
109 addr += BIAS;
78a0fd57 110
81f726ab
DM
111 for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
112 {
113 trad_frame_set_reg_addr (this_cache, regnum, addr);
114 addr += 8;
115 }
116 trad_frame_set_id (this_cache, frame_id_build (base, func));
78a0fd57 117}
58afddc6 118
0e42f66a 119/* sparc64 GNU/Linux implementation of the report_signal_info
58afddc6
WP
120 gdbarch hook.
121 Displays information related to ADI memory corruptions. */
122
cb8c24b6 123static void
0e42f66a
JB
124sparc64_linux_report_signal_info (struct gdbarch *gdbarch, struct ui_out *uiout,
125 enum gdb_signal siggnal)
58afddc6 126{
0e42f66a
JB
127 if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word != 64
128 || siggnal != GDB_SIGNAL_SEGV)
58afddc6
WP
129 return;
130
131 CORE_ADDR addr = 0;
132 long si_code = 0;
133
a70b8144 134 try
58afddc6
WP
135 {
136 /* Evaluate si_code to see if the segfault is ADI related. */
137 si_code = parse_and_eval_long ("$_siginfo.si_code\n");
138
139 if (si_code >= SEGV_ACCADI && si_code <= SEGV_ADIPERR)
dda83cd7 140 addr = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
58afddc6 141 }
b1ffd112 142 catch (const gdb_exception_error &exception)
58afddc6
WP
143 {
144 return;
145 }
58afddc6
WP
146
147 /* Print out ADI event based on sig_code value */
148 switch (si_code)
149 {
150 case SEGV_ACCADI: /* adi not enabled */
151 uiout->text ("\n");
152 uiout->field_string ("sigcode-meaning", _("ADI disabled"));
153 uiout->text (_(" while accessing address "));
ca8d69be 154 uiout->field_core_addr ("bound-access", gdbarch, addr);
58afddc6
WP
155 break;
156 case SEGV_ADIDERR: /* disrupting mismatch */
157 uiout->text ("\n");
158 uiout->field_string ("sigcode-meaning", _("ADI deferred mismatch"));
159 uiout->text (_(" while accessing address "));
ca8d69be 160 uiout->field_core_addr ("bound-access", gdbarch, addr);
58afddc6
WP
161 break;
162 case SEGV_ADIPERR: /* precise mismatch */
163 uiout->text ("\n");
164 uiout->field_string ("sigcode-meaning", _("ADI precise mismatch"));
165 uiout->text (_(" while accessing address "));
ca8d69be 166 uiout->field_core_addr ("bound-access", gdbarch, addr);
58afddc6
WP
167 break;
168 default:
169 break;
170 }
171
172}
173
78a0fd57 174\f
0b4294d3
DM
175/* Return the address of a system call's alternative return
176 address. */
177
178static CORE_ADDR
8480a37e 179sparc64_linux_step_trap (const frame_info_ptr &frame, unsigned long insn)
0b4294d3 180{
401e27fd
JM
181 /* __NR_rt_sigreturn is 101 */
182 if ((insn == 0x91d0206d)
183 && (get_frame_register_unsigned (frame, SPARC_G1_REGNUM) == 101))
0b4294d3 184 {
e17a4113
UW
185 struct gdbarch *gdbarch = get_frame_arch (frame);
186 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
187
0b1b3e42 188 ULONGEST sp = get_frame_register_unsigned (frame, SPARC_SP_REGNUM);
0b4294d3
DM
189 if (sp & 1)
190 sp += BIAS;
191
192 /* The kernel puts the sigreturn registers on the stack,
193 and this is where the signal unwinding state is take from
194 when returning from a signal.
195
196 A siginfo_t sits 192 bytes from the base of the stack. This
197 siginfo_t is 128 bytes, and is followed by the sigreturn
198 register save area. The saved PC sits at a 136 byte offset
199 into there. */
200
e17a4113
UW
201 return read_memory_unsigned_integer (sp + 192 + 128 + 136,
202 8, byte_order);
0b4294d3
DM
203 }
204
205 return 0;
206}
207\f
70f1dc74 208
b4fd25c9 209const struct sparc_gregmap sparc64_linux_core_gregmap =
07c5f590
DM
210{
211 32 * 8, /* %tstate */
212 33 * 8, /* %tpc */
213 34 * 8, /* %tnpc */
214 35 * 8, /* %y */
215 -1, /* %wim */
216 -1, /* %tbr */
217 1 * 8, /* %g1 */
218 16 * 8, /* %l0 */
219 8, /* y size */
220};
221\f
222
223static void
224sparc64_linux_supply_core_gregset (const struct regset *regset,
225 struct regcache *regcache,
226 int regnum, const void *gregs, size_t len)
227{
b4fd25c9 228 sparc64_supply_gregset (&sparc64_linux_core_gregmap,
c378eb4e 229 regcache, regnum, gregs);
07c5f590
DM
230}
231
232static void
233sparc64_linux_collect_core_gregset (const struct regset *regset,
234 const struct regcache *regcache,
235 int regnum, void *gregs, size_t len)
236{
b4fd25c9 237 sparc64_collect_gregset (&sparc64_linux_core_gregmap,
c378eb4e 238 regcache, regnum, gregs);
07c5f590
DM
239}
240
241static void
242sparc64_linux_supply_core_fpregset (const struct regset *regset,
243 struct regcache *regcache,
244 int regnum, const void *fpregs, size_t len)
245{
b4fd25c9 246 sparc64_supply_fpregset (&sparc64_bsd_fpregmap, regcache, regnum, fpregs);
07c5f590
DM
247}
248
249static void
250sparc64_linux_collect_core_fpregset (const struct regset *regset,
251 const struct regcache *regcache,
252 int regnum, void *fpregs, size_t len)
253{
b4fd25c9 254 sparc64_collect_fpregset (&sparc64_bsd_fpregmap, regcache, regnum, fpregs);
07c5f590
DM
255}
256
e8467b5a
DM
257/* Set the program counter for process PTID to PC. */
258
259#define TSTATE_SYSCALL 0x0000000000000020ULL
260
261static void
262sparc64_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
263{
345bd07c 264 gdbarch *arch = regcache->arch ();
08106042 265 sparc_gdbarch_tdep *tdep = gdbarch_tdep<sparc_gdbarch_tdep> (arch);
e8467b5a
DM
266 ULONGEST state;
267
268 regcache_cooked_write_unsigned (regcache, tdep->pc_regnum, pc);
269 regcache_cooked_write_unsigned (regcache, tdep->npc_regnum, pc + 4);
270
271 /* Clear the "in syscall" bit to prevent the kernel from
272 messing with the PCs we just installed, if we happen to be
273 within an interrupted system call that the kernel wants to
274 restart.
275
276 Note that after we return from the dummy call, the TSTATE et al.
277 registers will be automatically restored, and the kernel
278 continues to restart the system call at this point. */
279 regcache_cooked_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
280 state &= ~TSTATE_SYSCALL;
281 regcache_cooked_write_unsigned (regcache, SPARC64_STATE_REGNUM, state);
282}
283
09de9781
DM
284static LONGEST
285sparc64_linux_get_syscall_number (struct gdbarch *gdbarch,
00431a78 286 thread_info *thread)
09de9781 287{
00431a78 288 struct regcache *regcache = get_thread_regcache (thread);
09de9781
DM
289 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
290 /* The content of a register. */
291 gdb_byte buf[8];
292 /* The result. */
293 LONGEST ret;
294
295 /* Getting the system call number from the register.
296 When dealing with the sparc architecture, this information
297 is stored at the %g1 register. */
dca08e1f 298 regcache->cooked_read (SPARC_G1_REGNUM, buf);
09de9781
DM
299
300 ret = extract_signed_integer (buf, 8, byte_order);
301
302 return ret;
303}
304
d0b5971a
JM
305\f
306/* Implement the "get_longjmp_target" gdbarch method. */
307
308static int
8480a37e 309sparc64_linux_get_longjmp_target (const frame_info_ptr &frame, CORE_ADDR *pc)
d0b5971a
JM
310{
311 struct gdbarch *gdbarch = get_frame_arch (frame);
d0b5971a
JM
312 CORE_ADDR jb_addr;
313 gdb_byte buf[8];
314
315 jb_addr = get_frame_register_unsigned (frame, SPARC_O0_REGNUM);
316
317 /* setjmp and longjmp in SPARC64 are implemented in glibc using the
318 setcontext and getcontext system calls respectively. These
319 system calls operate on ucontext_t structures, which happen to
320 partially have the same structure than jmp_buf. However the
321 ucontext returned by getcontext, and thus the jmp_buf structure
322 returned by setjmp, contains the context of the trap instruction
323 in the glibc __[sig]setjmp wrapper, not the context of the user
324 code calling setjmp.
325
326 %o7 in the jmp_buf structure is stored at offset 18*8 in the
327 mc_gregs array, which is itself located at offset 32 into
328 jmp_buf. See bits/setjmp.h. This register contains the address
329 of the 'call setjmp' instruction in user code.
330
331 In order to determine the longjmp target address in the
332 initiating frame we need to examine the call instruction itself,
333 in particular whether the annul bit is set. If it is not set
334 then we need to jump over the instruction at the delay slot. */
335
336 if (target_read_memory (jb_addr + 32 + (18 * 8), buf, 8))
337 return 0;
338
339 *pc = extract_unsigned_integer (buf, 8, gdbarch_byte_order (gdbarch));
340
341 if (!sparc_is_annulled_branch_insn (*pc))
342 *pc += 4; /* delay slot insn */
343 *pc += 4; /* call insn */
344
345 return 1;
346}
347
07c5f590
DM
348\f
349
b13feb94
AA
350static const struct regset sparc64_linux_gregset =
351 {
352 NULL,
353 sparc64_linux_supply_core_gregset,
354 sparc64_linux_collect_core_gregset
355 };
356
357static const struct regset sparc64_linux_fpregset =
358 {
359 NULL,
360 sparc64_linux_supply_core_fpregset,
361 sparc64_linux_collect_core_fpregset
362 };
363
386c036b
MK
364static void
365sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
366{
08106042 367 sparc_gdbarch_tdep *tdep = gdbarch_tdep<sparc_gdbarch_tdep> (gdbarch);
386c036b 368
480af54c 369 linux_init_abi (info, gdbarch, 0);
a5ee0f0c 370
b13feb94 371 tdep->gregset = &sparc64_linux_gregset;
07c5f590
DM
372 tdep->sizeof_gregset = 288;
373
b13feb94 374 tdep->fpregset = &sparc64_linux_fpregset;
07c5f590
DM
375 tdep->sizeof_fpregset = 280;
376
81f726ab 377 tramp_frame_prepend_unwinder (gdbarch, &sparc64_linux_rt_sigframe);
78a0fd57 378
b2a0b9b2 379 /* Hook in the DWARF CFI frame unwinder. */
87a7da84 380 dwarf2_append_unwinders (gdbarch);
b2a0b9b2 381
20338726
DM
382 sparc64_init_abi (info, gdbarch);
383
a33e488c
MK
384 /* GNU/Linux has SVR4-style shared libraries... */
385 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
386 set_solib_svr4_fetch_link_map_offsets
c0154a4a 387 (gdbarch, linux_lp64_fetch_link_map_offsets);
386c036b 388
a33e488c
MK
389 /* ...which means that we need some special handling when doing
390 prologue analysis. */
391 tdep->plt_entry_size = 16;
b2756930
KB
392
393 /* Enable TLS support. */
394 set_gdbarch_fetch_tls_load_module_address (gdbarch,
dda83cd7 395 svr4_fetch_objfile_link_map);
0b4294d3
DM
396
397 /* Make sure we can single-step over signal return system calls. */
398 tdep->step_trap = sparc64_linux_step_trap;
e8467b5a 399
d0b5971a
JM
400 /* Make sure we can single-step over longjmp calls. */
401 set_gdbarch_get_longjmp_target (gdbarch, sparc64_linux_get_longjmp_target);
402
e8467b5a 403 set_gdbarch_write_pc (gdbarch, sparc64_linux_write_pc);
09de9781
DM
404
405 /* Functions for 'catch syscall'. */
458c8db8 406 set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_SPARC64);
09de9781 407 set_gdbarch_get_syscall_number (gdbarch,
dda83cd7 408 sparc64_linux_get_syscall_number);
0e42f66a 409 set_gdbarch_report_signal_info (gdbarch, sparc64_linux_report_signal_info);
386c036b 410}
386c036b 411
6c265988 412void _initialize_sparc64_linux_tdep ();
386c036b 413void
6c265988 414_initialize_sparc64_linux_tdep ()
386c036b
MK
415{
416 gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
417 GDB_OSABI_LINUX, sparc64_linux_init_abi);
418}