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