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