tic6x-linux-tdep.c revision 1.8 1 1.1 christos /* GNU/Linux on TI C6x target support.
2 1.8 christos Copyright (C) 2011-2019 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.1 christos
30 1.1 christos /* The offset from rt_sigframe pointer to SP register. */
31 1.1 christos #define TIC6X_SP_RT_SIGFRAME 8
32 1.1 christos /* Size of struct siginfo info. */
33 1.1 christos #define TIC6X_SIGINFO_SIZE 128
34 1.1 christos /* Size of type stack_t, which contains three fields of type void*, int, and
35 1.1 christos size_t respectively. */
36 1.1 christos #define TIC6X_STACK_T_SIZE (3 * 4)
37 1.1 christos
38 1.1 christos static const gdb_byte tic6x_bkpt_bnop_be[] = { 0x00, 0x00, 0xa1, 0x22 };
39 1.1 christos static const gdb_byte tic6x_bkpt_bnop_le[] = { 0x22, 0xa1, 0x00, 0x00 };
40 1.1 christos
41 1.1 christos /* Return the offset of register REGNUM in struct sigcontext. Return 0 if no
42 1.1 christos such register in sigcontext. */
43 1.1 christos
44 1.1 christos static unsigned int
45 1.1 christos tic6x_register_sigcontext_offset (unsigned int regnum, struct gdbarch *gdbarch)
46 1.1 christos {
47 1.1 christos struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
48 1.1 christos
49 1.1 christos if (regnum == TIC6X_A4_REGNUM || regnum == TIC6X_A4_REGNUM + 2
50 1.1 christos || regnum == TIC6X_A4_REGNUM + 4)
51 1.1 christos return 4 * (regnum - TIC6X_A4_REGNUM + 2); /* A4, A6, A8 */
52 1.1 christos else if (regnum == TIC6X_A5_REGNUM || regnum == TIC6X_A5_REGNUM + 2
53 1.1 christos || regnum == TIC6X_A5_REGNUM + 4)
54 1.1 christos return 4 * (regnum - TIC6X_A5_REGNUM + 12); /* A5, A7, A9 */
55 1.1 christos else if (regnum == TIC6X_B4_REGNUM || regnum == TIC6X_B4_REGNUM + 2
56 1.1 christos || regnum == TIC6X_B4_REGNUM + 4)
57 1.1 christos return 4 * (regnum - TIC6X_B4_REGNUM + 3); /* B4, B6, B8 */
58 1.1 christos else if (regnum == TIC6X_B5_REGNUM || regnum == TIC6X_B5_REGNUM + 2
59 1.1 christos || regnum == TIC6X_B5_REGNUM + 4)
60 1.1 christos return 4 * (regnum - TIC6X_B5_REGNUM + 19); /* B5, B7, B9 */
61 1.1 christos else if (regnum < TIC6X_A4_REGNUM)
62 1.1 christos return 4 * (regnum - 0 + 8); /* A0 - A3 */
63 1.1 christos else if (regnum >= TIC6X_B0_REGNUM && regnum < TIC6X_B4_REGNUM)
64 1.1 christos return 4 * (regnum - TIC6X_B0_REGNUM + 15); /* B0 - B3 */
65 1.1 christos else if (regnum >= 34 && regnum < 34 + 32)
66 1.1 christos return 4 * (regnum - 34 + 23); /* A16 - A31, B16 - B31 */
67 1.1 christos else if (regnum == TIC6X_PC_REGNUM)
68 1.1 christos return 4 * (tdep->has_gp ? 55 : 23);
69 1.1 christos else if (regnum == TIC6X_SP_REGNUM)
70 1.1 christos return 4;
71 1.1 christos
72 1.1 christos return 0;
73 1.1 christos }
74 1.1 christos
75 1.1 christos /* Support unwinding frame in signal trampoline. We don't check sigreturn,
76 1.1 christos since it is not used in kernel. */
77 1.1 christos
78 1.1 christos static void
79 1.1 christos tic6x_linux_rt_sigreturn_init (const struct tramp_frame *self,
80 1.1 christos struct frame_info *this_frame,
81 1.1 christos struct trad_frame_cache *this_cache,
82 1.1 christos CORE_ADDR func)
83 1.1 christos {
84 1.1 christos struct gdbarch *gdbarch = get_frame_arch (this_frame);
85 1.1 christos CORE_ADDR sp = get_frame_register_unsigned (this_frame, TIC6X_SP_REGNUM);
86 1.1 christos /* The base of struct sigcontext is computed by examining the definition of
87 1.1 christos struct rt_sigframe in linux kernel source arch/c6x/kernel/signal.c. */
88 1.1 christos CORE_ADDR base = (sp + TIC6X_SP_RT_SIGFRAME
89 1.1 christos /* Pointer type *pinfo and *puc in struct rt_sigframe. */
90 1.1 christos + 4 + 4
91 1.1 christos + TIC6X_SIGINFO_SIZE
92 1.1 christos + 4 + 4 /* uc_flags and *uc_link in struct ucontext. */
93 1.1 christos + TIC6X_STACK_T_SIZE);
94 1.1 christos struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
95 1.1 christos unsigned int reg_offset;
96 1.1 christos unsigned int i;
97 1.1 christos
98 1.1 christos for (i = 0; i < 10; i++) /* A0 - A9 */
99 1.1 christos {
100 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
101 1.1 christos gdb_assert (reg_offset != 0);
102 1.1 christos
103 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
104 1.1 christos }
105 1.1 christos
106 1.1 christos for (i = TIC6X_B0_REGNUM; i < TIC6X_B0_REGNUM + 10; i++) /* B0 - B9 */
107 1.1 christos {
108 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
109 1.1 christos gdb_assert (reg_offset != 0);
110 1.1 christos
111 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
112 1.1 christos }
113 1.1 christos
114 1.1 christos if (tdep->has_gp)
115 1.1 christos for (i = 34; i < 34 + 32; i++) /* A16 - A31, B16 - B31 */
116 1.1 christos {
117 1.1 christos reg_offset = tic6x_register_sigcontext_offset (i, gdbarch);
118 1.1 christos gdb_assert (reg_offset != 0);
119 1.1 christos
120 1.1 christos trad_frame_set_reg_addr (this_cache, i, base + reg_offset);
121 1.1 christos }
122 1.1 christos
123 1.1 christos trad_frame_set_reg_addr (this_cache, TIC6X_PC_REGNUM,
124 1.1 christos base + tic6x_register_sigcontext_offset (TIC6X_PC_REGNUM,
125 1.1 christos gdbarch));
126 1.1 christos trad_frame_set_reg_addr (this_cache, TIC6X_SP_REGNUM,
127 1.1 christos base + tic6x_register_sigcontext_offset (TIC6X_SP_REGNUM,
128 1.1 christos gdbarch));
129 1.1 christos
130 1.1 christos /* Save a frame ID. */
131 1.1 christos trad_frame_set_id (this_cache, frame_id_build (sp, func));
132 1.1 christos }
133 1.1 christos
134 1.1 christos static struct tramp_frame tic6x_linux_rt_sigreturn_tramp_frame =
135 1.1 christos {
136 1.1 christos SIGTRAMP_FRAME,
137 1.1 christos 4,
138 1.1 christos {
139 1.1 christos {0x000045aa, 0x0fffffff}, /* mvk .S2 139,b0 */
140 1.8 christos {0x10000000, ULONGEST_MAX}, /* swe */
141 1.1 christos {TRAMP_SENTINEL_INSN}
142 1.1 christos },
143 1.1 christos tic6x_linux_rt_sigreturn_init
144 1.1 christos };
145 1.1 christos
146 1.1 christos /* When FRAME is at a syscall instruction, return the PC of the next
147 1.1 christos instruction to be executed. */
148 1.1 christos
149 1.1 christos static CORE_ADDR
150 1.1 christos tic6x_linux_syscall_next_pc (struct frame_info *frame)
151 1.1 christos {
152 1.1 christos ULONGEST syscall_number = get_frame_register_unsigned (frame,
153 1.1 christos TIC6X_B0_REGNUM);
154 1.1 christos CORE_ADDR pc = get_frame_pc (frame);
155 1.1 christos
156 1.1 christos if (syscall_number == 139 /* rt_sigreturn */)
157 1.1 christos return frame_unwind_caller_pc (frame);
158 1.1 christos
159 1.1 christos return pc + 4;
160 1.1 christos }
161 1.1 christos
162 1.1 christos
163 1.1 christos extern struct target_so_ops dsbt_so_ops;
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.1 christos struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
168 1.1 christos
169 1.1 christos linux_init_abi (info, gdbarch);
170 1.1 christos
171 1.1 christos /* Shared library handling. */
172 1.1 christos set_solib_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.1 christos void
207 1.1 christos _initialize_tic6x_linux_tdep (void)
208 1.1 christos {
209 1.1 christos gdbarch_register_osabi (bfd_arch_tic6x, 0, GDB_OSABI_LINUX,
210 1.1 christos tic6x_uclinux_init_abi);
211 1.1 christos }
212