tic6x-linux-tdep.c revision 1.10 1 1.1 christos /* GNU/Linux on TI C6x target support.
2 1.10 christos Copyright (C) 2011-2023 Free Software Foundation, Inc.
3 1.1 christos Contributed by Yao Qi <yao (at) codesourcery.com>
4 1.1 christos
5 1.1 christos This file is part of GDB.
6 1.1 christos
7 1.1 christos This program is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos This program is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 christos GNU General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 1.1 christos
20 1.1 christos #include "defs.h"
21 1.1 christos #include "solib.h"
22 1.1 christos #include "osabi.h"
23 1.1 christos #include "linux-tdep.h"
24 1.1 christos #include "tic6x-tdep.h"
25 1.1 christos #include "trad-frame.h"
26 1.1 christos #include "tramp-frame.h"
27 1.1 christos #include "elf-bfd.h"
28 1.1 christos #include "elf/tic6x.h"
29 1.9 christos #include "gdbarch.h"
30 1.10 christos #include "solib-dsbt.h"
31 1.1 christos
32 1.1 christos /* The offset from rt_sigframe pointer to SP register. */
33 1.1 christos #define TIC6X_SP_RT_SIGFRAME 8
34 1.1 christos /* Size of struct siginfo info. */
35 1.1 christos #define TIC6X_SIGINFO_SIZE 128
36 1.1 christos /* Size of type stack_t, which contains three fields of type void*, int, and
37 1.1 christos size_t respectively. */
38 1.1 christos #define TIC6X_STACK_T_SIZE (3 * 4)
39 1.1 christos
40 1.1 christos static const gdb_byte tic6x_bkpt_bnop_be[] = { 0x00, 0x00, 0xa1, 0x22 };
41 1.1 christos static const gdb_byte tic6x_bkpt_bnop_le[] = { 0x22, 0xa1, 0x00, 0x00 };
42 1.1 christos
43 1.1 christos /* Return the offset of register REGNUM in struct sigcontext. Return 0 if no
44 1.1 christos such register in sigcontext. */
45 1.1 christos
46 1.1 christos static unsigned int
47 1.1 christos tic6x_register_sigcontext_offset (unsigned int regnum, struct gdbarch *gdbarch)
48 1.1 christos {
49 1.10 christos tic6x_gdbarch_tdep *tdep = gdbarch_tdep<tic6x_gdbarch_tdep> (gdbarch);
50 1.1 christos
51 1.1 christos if (regnum == TIC6X_A4_REGNUM || regnum == TIC6X_A4_REGNUM + 2
52 1.1 christos || regnum == TIC6X_A4_REGNUM + 4)
53 1.1 christos return 4 * (regnum - TIC6X_A4_REGNUM + 2); /* A4, A6, A8 */
54 1.1 christos else if (regnum == TIC6X_A5_REGNUM || regnum == TIC6X_A5_REGNUM + 2
55 1.1 christos || regnum == TIC6X_A5_REGNUM + 4)
56 1.1 christos return 4 * (regnum - TIC6X_A5_REGNUM + 12); /* A5, A7, A9 */
57 1.1 christos else if (regnum == TIC6X_B4_REGNUM || regnum == TIC6X_B4_REGNUM + 2
58 1.1 christos || regnum == TIC6X_B4_REGNUM + 4)
59 1.1 christos return 4 * (regnum - TIC6X_B4_REGNUM + 3); /* B4, B6, B8 */
60 1.1 christos else if (regnum == TIC6X_B5_REGNUM || regnum == TIC6X_B5_REGNUM + 2
61 1.1 christos || regnum == TIC6X_B5_REGNUM + 4)
62 1.1 christos return 4 * (regnum - TIC6X_B5_REGNUM + 19); /* B5, B7, B9 */
63 1.1 christos else if (regnum < TIC6X_A4_REGNUM)
64 1.1 christos return 4 * (regnum - 0 + 8); /* A0 - A3 */
65 1.1 christos else if (regnum >= TIC6X_B0_REGNUM && regnum < TIC6X_B4_REGNUM)
66 1.1 christos return 4 * (regnum - TIC6X_B0_REGNUM + 15); /* B0 - B3 */
67 1.1 christos else if (regnum >= 34 && regnum < 34 + 32)
68 1.1 christos return 4 * (regnum - 34 + 23); /* A16 - A31, B16 - B31 */
69 1.1 christos else if (regnum == TIC6X_PC_REGNUM)
70 1.1 christos return 4 * (tdep->has_gp ? 55 : 23);
71 1.1 christos else if (regnum == TIC6X_SP_REGNUM)
72 1.1 christos return 4;
73 1.1 christos
74 1.1 christos return 0;
75 1.1 christos }
76 1.1 christos
77 1.1 christos /* Support unwinding frame in signal trampoline. We don't check sigreturn,
78 1.1 christos since it is not used in kernel. */
79 1.1 christos
80 1.1 christos static void
81 1.1 christos tic6x_linux_rt_sigreturn_init (const struct tramp_frame *self,
82 1.10 christos frame_info_ptr this_frame,
83 1.1 christos struct trad_frame_cache *this_cache,
84 1.1 christos CORE_ADDR func)
85 1.1 christos {
86 1.1 christos struct gdbarch *gdbarch = get_frame_arch (this_frame);
87 1.1 christos CORE_ADDR sp = get_frame_register_unsigned (this_frame, TIC6X_SP_REGNUM);
88 1.1 christos /* The base of struct sigcontext is computed by examining the definition of
89 1.1 christos struct rt_sigframe in linux kernel source arch/c6x/kernel/signal.c. */
90 1.1 christos CORE_ADDR base = (sp + TIC6X_SP_RT_SIGFRAME
91 1.1 christos /* Pointer type *pinfo and *puc in struct rt_sigframe. */
92 1.1 christos + 4 + 4
93 1.1 christos + TIC6X_SIGINFO_SIZE
94 1.1 christos + 4 + 4 /* uc_flags and *uc_link in struct ucontext. */
95 1.1 christos + TIC6X_STACK_T_SIZE);
96 1.10 christos tic6x_gdbarch_tdep *tdep = gdbarch_tdep<tic6x_gdbarch_tdep> (gdbarch);
97 1.1 christos unsigned int reg_offset;
98 1.1 christos unsigned int i;
99 1.1 christos
100 1.1 christos for (i = 0; i < 10; i++) /* A0 - A9 */
101 1.1 christos {
102 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
103 1.1 christos gdb_assert (reg_offset != 0);
104 1.1 christos
105 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
106 1.1 christos }
107 1.1 christos
108 1.1 christos for (i = TIC6X_B0_REGNUM; i < TIC6X_B0_REGNUM + 10; i++) /* B0 - B9 */
109 1.1 christos {
110 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
111 1.1 christos gdb_assert (reg_offset != 0);
112 1.1 christos
113 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
114 1.1 christos }
115 1.1 christos
116 1.1 christos if (tdep->has_gp)
117 1.1 christos for (i = 34; i < 34 + 32; i++) /* A16 - A31, B16 - B31 */
118 1.1 christos {
119 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
120 1.1 christos gdb_assert (reg_offset != 0);
121 1.1 christos
122 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
123 1.1 christos }
124 1.1 christos
125 1.1 christos trad_frame_set_reg_addr (this_cache, TIC6X_PC_REGNUM,
126 1.1 christos base + tic6x_register_sigcontext_offset (TIC6X_PC_REGNUM,
127 1.1 christos gdbarch));
128 1.1 christos trad_frame_set_reg_addr (this_cache, TIC6X_SP_REGNUM,
129 1.1 christos base + tic6x_register_sigcontext_offset (TIC6X_SP_REGNUM,
130 1.1 christos gdbarch));
131 1.1 christos
132 1.1 christos /* Save a frame ID. */
133 1.1 christos trad_frame_set_id (this_cache, frame_id_build (sp, func));
134 1.1 christos }
135 1.1 christos
136 1.1 christos static struct tramp_frame tic6x_linux_rt_sigreturn_tramp_frame =
137 1.1 christos {
138 1.1 christos SIGTRAMP_FRAME,
139 1.1 christos 4,
140 1.1 christos {
141 1.1 christos {0x000045aa, 0x0fffffff}, /* mvk .S2 139,b0 */
142 1.8 christos {0x10000000, ULONGEST_MAX}, /* swe */
143 1.1 christos {TRAMP_SENTINEL_INSN}
144 1.1 christos },
145 1.1 christos tic6x_linux_rt_sigreturn_init
146 1.1 christos };
147 1.1 christos
148 1.1 christos /* When FRAME is at a syscall instruction, return the PC of the next
149 1.1 christos instruction to be executed. */
150 1.1 christos
151 1.1 christos static CORE_ADDR
152 1.10 christos tic6x_linux_syscall_next_pc (frame_info_ptr frame)
153 1.1 christos {
154 1.1 christos ULONGEST syscall_number = get_frame_register_unsigned (frame,
155 1.1 christos TIC6X_B0_REGNUM);
156 1.1 christos CORE_ADDR pc = get_frame_pc (frame);
157 1.1 christos
158 1.1 christos if (syscall_number == 139 /* rt_sigreturn */)
159 1.1 christos return frame_unwind_caller_pc (frame);
160 1.1 christos
161 1.1 christos return pc + 4;
162 1.1 christos }
163 1.1 christos
164 1.1 christos
165 1.1 christos static void
166 1.1 christos tic6x_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
167 1.1 christos {
168 1.10 christos tic6x_gdbarch_tdep *tdep = gdbarch_tdep<tic6x_gdbarch_tdep> (gdbarch);
169 1.1 christos
170 1.10 christos linux_init_abi (info, gdbarch, 0);
171 1.1 christos
172 1.1 christos /* Shared library handling. */
173 1.10 christos set_gdbarch_so_ops (gdbarch, &dsbt_so_ops);
174 1.1 christos
175 1.1 christos tdep->syscall_next_pc = tic6x_linux_syscall_next_pc;
176 1.1 christos
177 1.1 christos #ifdef HAVE_ELF
178 1.1 christos /* In tic6x Linux kernel, breakpoint instructions varies on different archs.
179 1.1 christos On C64x+ and C67x+, breakpoint instruction is 0x56454314, which is an
180 1.1 christos illegal opcode. On other arch, breakpoint instruction is 0x0000a122
181 1.1 christos (BNOP .S2 0,5). */
182 1.1 christos if (info.abfd)
183 1.1 christos switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC, Tag_ISA))
184 1.1 christos {
185 1.1 christos case C6XABI_Tag_ISA_C64XP:
186 1.1 christos case C6XABI_Tag_ISA_C67XP:
187 1.1 christos if (info.byte_order == BFD_ENDIAN_BIG)
188 1.1 christos tdep->breakpoint = tic6x_bkpt_illegal_opcode_be;
189 1.1 christos else
190 1.1 christos tdep->breakpoint = tic6x_bkpt_illegal_opcode_le;
191 1.1 christos break;
192 1.1 christos default:
193 1.1 christos {
194 1.1 christos if (info.byte_order == BFD_ENDIAN_BIG)
195 1.1 christos tdep->breakpoint = tic6x_bkpt_bnop_be;
196 1.1 christos else
197 1.1 christos tdep->breakpoint = tic6x_bkpt_bnop_le;
198 1.1 christos }
199 1.1 christos }
200 1.1 christos #endif
201 1.1 christos
202 1.1 christos /* Signal trampoline support. */
203 1.1 christos tramp_frame_prepend_unwinder (gdbarch,
204 1.1 christos &tic6x_linux_rt_sigreturn_tramp_frame);
205 1.1 christos }
206 1.1 christos
207 1.9 christos void _initialize_tic6x_linux_tdep ();
208 1.1 christos void
209 1.9 christos _initialize_tic6x_linux_tdep ()
210 1.1 christos {
211 1.1 christos gdbarch_register_osabi (bfd_arch_tic6x, 0, GDB_OSABI_LINUX,
212 1.1 christos tic6x_uclinux_init_abi);
213 1.1 christos }
214