diff options
author | Yao Qi <yao@codesourcery.com> | 2011-08-14 14:03:45 +0000 |
---|---|---|
committer | Yao Qi <yao@codesourcery.com> | 2011-08-14 14:03:45 +0000 |
commit | 8cd64e0034dc4dc3e48245f9f61fd1f5245fce66 (patch) | |
tree | ae14a68d55ae52a375669ffb8aa8b6ea12904988 /gdb/tic6x-linux-tdep.c | |
parent | 78d8519916ea5cc108bb6280779e0384978fa6d2 (diff) | |
download | gdb-8cd64e0034dc4dc3e48245f9f61fd1f5245fce66.zip gdb-8cd64e0034dc4dc3e48245f9f61fd1f5245fce66.tar.gz gdb-8cd64e0034dc4dc3e48245f9f61fd1f5245fce66.tar.bz2 |
gdb/
* configure.tgt: Handle tic6x-*-*linux and tic6x-*-*.
* solib-dsbt.c: New file. Support DSBT shared object.
* tic6x-linux-tdep.c: New file.
* tic6x-tdep.c: New file.
* tic6x-tdep.h: New file.
Diffstat (limited to 'gdb/tic6x-linux-tdep.c')
-rw-r--r-- | gdb/tic6x-linux-tdep.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/gdb/tic6x-linux-tdep.c b/gdb/tic6x-linux-tdep.c new file mode 100644 index 0000000..0e4d327 --- /dev/null +++ b/gdb/tic6x-linux-tdep.c @@ -0,0 +1,227 @@ +/* GNU/Linux on TI C6x target support. + Copyright (C) 2011 + Free Software Foundation, Inc. + Contributed by Yao Qi <yao@codesourcery.com> + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "solib.h" +#include "osabi.h" +#include "linux-tdep.h" +#include "tic6x-tdep.h" +#include "trad-frame.h" +#include "tramp-frame.h" +#include "gdb_assert.h" +#include "elf-bfd.h" +#include "elf/tic6x.h" + +#include "features/tic6x-c64xp-linux.c" +#include "features/tic6x-c64x-linux.c" +#include "features/tic6x-c62x-linux.c" + +/* The offset from rt_sigframe pointer to SP register. */ +#define TIC6X_SP_RT_SIGFRAME 8 +/* Size of struct siginfo info. */ +#define TIC6X_SIGINFO_SIZE 128 +/* Size of type stack_t, which contains three fields of type void*, int, and + size_t respectively. */ +#define TIC6X_STACK_T_SIZE (3 * 4) + +const gdb_byte tic6x_bkpt_illegal_opcode_be[] = { 0x56, 0x45, 0x43, 0x14 }; +const gdb_byte tic6x_bkpt_illegal_opcode_le[] = { 0x14, 0x43, 0x45, 0x56 }; + +static const gdb_byte tic6x_bkpt_bnop_be[] = { 0x00, 0x00, 0xa1, 0x22 }; +static const gdb_byte tic6x_bkpt_bnop_le[] = { 0x22, 0xa1, 0x00, 0x00 }; + +/* Return the offset of register REGNUM in struct sigcontext. Return 0 if no + such register in sigcontext. */ + +static unsigned int +tic6x_register_sigcontext_offset (unsigned int regnum, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (regnum == TIC6X_A4_REGNUM || regnum == TIC6X_A4_REGNUM + 2 + || regnum == TIC6X_A4_REGNUM + 4) + return 4 * (regnum - TIC6X_A4_REGNUM + 2); /* A4, A6, A8 */ + else if (regnum == TIC6X_A5_REGNUM || regnum == TIC6X_A5_REGNUM + 2 + || regnum == TIC6X_A5_REGNUM + 4) + return 4 * (regnum - TIC6X_A5_REGNUM + 12); /* A5, A7, A9 */ + else if (regnum == TIC6X_B4_REGNUM || regnum == TIC6X_B4_REGNUM + 2 + || regnum == TIC6X_B4_REGNUM + 4) + return 4 * (regnum - TIC6X_B4_REGNUM + 3); /* B4, B6, B8 */ + else if (regnum == TIC6X_B5_REGNUM || regnum == TIC6X_B5_REGNUM + 2 + || regnum == TIC6X_B5_REGNUM + 4) + return 4 * (regnum - TIC6X_B5_REGNUM + 19); /* B5, B7, B9 */ + else if (regnum >= 0 && regnum < TIC6X_A4_REGNUM) + return 4 * (regnum - 0 + 8); /* A0 - A3 */ + else if (regnum >= TIC6X_B0_REGNUM && regnum < TIC6X_B4_REGNUM) + return 4 * (regnum - TIC6X_B0_REGNUM + 15); /* B0 - B3 */ + else if (regnum >= 34 && regnum < 34 + 32) + return 4 * (regnum - 34 + 23); /* A16 - A31, B16 - B31 */ + else if (regnum == TIC6X_PC_REGNUM) + return 4 * (tdep->has_gp ? 55 : 23); + else if (regnum == TIC6X_SP_REGNUM) + return 4; + + return 0; +} + +/* Support unwinding frame in signal trampoline. We don't check sigreturn, + since it is not used in kernel. */ + +static void +tic6x_linux_rt_sigreturn_init (const struct tramp_frame *self, + struct frame_info *this_frame, + struct trad_frame_cache *this_cache, + CORE_ADDR func) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + CORE_ADDR sp = get_frame_register_unsigned (this_frame, TIC6X_SP_REGNUM); + /* The base of struct sigcontext is computed by examining the definition of + struct rt_sigframe in linux kernel source arch/c6x/kernel/signal.c. */ + CORE_ADDR base = (sp + TIC6X_SP_RT_SIGFRAME + /* Pointer type *pinfo and *puc in struct rt_sigframe. */ + + 4 + 4 + + TIC6X_SIGINFO_SIZE + + 4 + 4 /* uc_flags and *uc_link in struct ucontext. */ + + TIC6X_STACK_T_SIZE); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + unsigned int reg_offset; + unsigned int i; + + for (i = 0; i < 10; i++) /* A0 - A9 */ + { + reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); + gdb_assert (reg_offset != 0); + + trad_frame_set_reg_addr (this_cache, i, base + reg_offset); + } + + for (i = TIC6X_B0_REGNUM; i < TIC6X_B0_REGNUM + 10; i++) /* B0 - B9 */ + { + reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); + gdb_assert (reg_offset != 0); + + trad_frame_set_reg_addr (this_cache, i, base + reg_offset); + } + + if (tdep->has_gp) + for (i = 34; i < 34 + 32; i++) /* A16 - A31, B16 - B31 */ + { + reg_offset = tic6x_register_sigcontext_offset (i, gdbarch); + gdb_assert (reg_offset != 0); + + trad_frame_set_reg_addr (this_cache, i, base + reg_offset); + } + + trad_frame_set_reg_addr (this_cache, TIC6X_PC_REGNUM, + base + tic6x_register_sigcontext_offset (TIC6X_PC_REGNUM, + gdbarch)); + trad_frame_set_reg_addr (this_cache, TIC6X_SP_REGNUM, + base + tic6x_register_sigcontext_offset (TIC6X_SP_REGNUM, + gdbarch)); + + /* Save a frame ID. */ + trad_frame_set_id (this_cache, frame_id_build (sp, func)); +} + +static struct tramp_frame tic6x_linux_rt_sigreturn_tramp_frame = +{ + SIGTRAMP_FRAME, + 4, + { + {0x000045aa, 0x0fffffff}, /* mvk .S2 139,b0 */ + {0x10000000, -1}, /* swe */ + {TRAMP_SENTINEL_INSN} + }, + tic6x_linux_rt_sigreturn_init +}; + +/* When FRAME is at a syscall instruction, return the PC of the next + instruction to be executed. */ + +static CORE_ADDR +tic6x_linux_syscall_next_pc (struct frame_info *frame) +{ + ULONGEST syscall_number = get_frame_register_unsigned (frame, + TIC6X_B0_REGNUM); + CORE_ADDR pc = get_frame_pc (frame); + + if (syscall_number == 139 /* rt_sigreturn */) + return frame_unwind_caller_pc (frame); + + return pc + 4; +} + + +extern struct target_so_ops dsbt_so_ops; +static void +tic6x_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + linux_init_abi (info, gdbarch); + + /* Shared library handling. */ + set_solib_ops (gdbarch, &dsbt_so_ops); + + tdep->syscall_next_pc = tic6x_linux_syscall_next_pc; + +#ifdef HAVE_ELF + /* In tic6x Linux kernel, breakpoint instructions varies on different archs. + On C64x+ and C67x+, breakpoint instruction is 0x56454314, which is an + illegal opcode. On other arch, breakpoint instruction is 0x0000a122 + (BNOP .S2 0,5). */ + if (info.abfd) + switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_PROC, Tag_ISA)) + { + case C6XABI_Tag_ISA_C64XP: + case C6XABI_Tag_ISA_C67XP: + if (info.byte_order == BFD_ENDIAN_BIG) + tdep->breakpoint = tic6x_bkpt_illegal_opcode_be; + else + tdep->breakpoint = tic6x_bkpt_illegal_opcode_le; + break; + default: + { + if (info.byte_order == BFD_ENDIAN_BIG) + tdep->breakpoint = tic6x_bkpt_bnop_be; + else + tdep->breakpoint = tic6x_bkpt_bnop_le; + } + } +#endif + + /* Signal trampoline support. */ + tramp_frame_prepend_unwinder (gdbarch, + &tic6x_linux_rt_sigreturn_tramp_frame); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_tic6x_linux_tdep; + +void +_initialize_tic6x_linux_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_tic6x, 0, GDB_OSABI_LINUX, + tic6x_uclinux_init_abi); + + initialize_tdesc_tic6x_c64xp_linux (); + initialize_tdesc_tic6x_c64x_linux (); + initialize_tdesc_tic6x_c62x_linux (); +} |