| /* Target-dependent code for Analog Devices Blackfin processor, for GDB. |
| |
| Copyright (C) 2005-2021 Free Software Foundation, Inc. |
| |
| Contributed by Analog Devices, Inc. |
| |
| 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 "arch-utils.h" |
| #include "regcache.h" |
| #include "tramp-frame.h" |
| #include "trad-frame.h" |
| #include "osabi.h" |
| #include "xml-syscall.h" |
| #include "linux-tdep.h" |
| #include "bfin-tdep.h" |
| |
| /* From <asm/sigcontext.h>. */ |
| |
| #define SIGCONTEXT_OFFSET 168 |
| |
| static const int bfin_linux_sigcontext_reg_offset[BFIN_NUM_REGS] = |
| { |
| 0 * 4, /* %r0 */ |
| 1 * 4, /* %r1 */ |
| 2 * 4, /* %r2 */ |
| 3 * 4, /* %r3 */ |
| 4 * 4, /* %r4 */ |
| 5 * 4, /* %r5 */ |
| 6 * 4, /* %r6 */ |
| 7 * 4, /* %r7 */ |
| 8 * 4, /* %p0 */ |
| 9 * 4, /* %p1 */ |
| 10 * 4, /* %p2 */ |
| 11 * 4, /* %p3 */ |
| 12 * 4, /* %p4 */ |
| 13 * 4, /* %p5 */ |
| 14 * 4, /* %sp */ |
| 23 * 4, /* %fp */ |
| 24 * 4, /* %i0 */ |
| 25 * 4, /* %i1 */ |
| 26 * 4, /* %i2 */ |
| 27 * 4, /* %i3 */ |
| 28 * 4, /* %m0 */ |
| 29 * 4, /* %m1 */ |
| 30 * 4, /* %m2 */ |
| 31 * 4, /* %m3 */ |
| 36 * 4, /* %b0 */ |
| 37 * 4, /* %b1 */ |
| 38 * 4, /* %b2 */ |
| 39 * 4, /* %b3 */ |
| 32 * 4, /* %l0 */ |
| 33 * 4, /* %l1 */ |
| 34 * 4, /* %l2 */ |
| 35 * 4, /* %l3 */ |
| 17 * 4, /* %a0x */ |
| 15 * 4, /* %a0w */ |
| 18 * 4, /* %a1x */ |
| 16 * 4, /* %a1w */ |
| 19 * 4, /* %astat */ |
| 20 * 4, /* %rets */ |
| 40 * 4, /* %lc0 */ |
| 42 * 4, /* %lt0 */ |
| 44 * 4, /* %lb0 */ |
| 41 * 4, /* %lc1 */ |
| 43 * 4, /* %lt1 */ |
| 45 * 4, /* %lb1 */ |
| -1, /* %cycles */ |
| -1, /* %cycles2 */ |
| -1, /* %usp */ |
| 46 * 4, /* %seqstat */ |
| -1, /* syscfg */ |
| 21 * 4, /* %reti */ |
| 22 * 4, /* %retx */ |
| -1, /* %retn */ |
| -1, /* %rete */ |
| 21 * 4, /* %pc */ |
| }; |
| |
| /* Signal trampolines. */ |
| |
| static void |
| bfin_linux_sigframe_init (const struct tramp_frame *self, |
| struct frame_info *this_frame, |
| struct trad_frame_cache *this_cache, |
| CORE_ADDR func) |
| { |
| CORE_ADDR sp = get_frame_sp (this_frame); |
| CORE_ADDR pc = get_frame_pc (this_frame); |
| CORE_ADDR sigcontext = sp + SIGCONTEXT_OFFSET; |
| const int *reg_offset = bfin_linux_sigcontext_reg_offset; |
| int i; |
| |
| for (i = 0; i < BFIN_NUM_REGS; i++) |
| if (reg_offset[i] != -1) |
| trad_frame_set_reg_addr (this_cache, i, sigcontext + reg_offset[i]); |
| |
| /* This would come after the LINK instruction in the ret_from_signal |
| function, hence the frame id would be SP + 8. */ |
| trad_frame_set_id (this_cache, frame_id_build (sp + 8, pc)); |
| } |
| |
| static const struct tramp_frame bfin_linux_sigframe = |
| { |
| SIGTRAMP_FRAME, |
| 4, |
| { |
| { 0x00ADE128, 0xffffffff }, /* P0 = __NR_rt_sigreturn; */ |
| { 0x00A0, 0xffff }, /* EXCPT 0; */ |
| { TRAMP_SENTINEL_INSN, ULONGEST_MAX }, |
| }, |
| bfin_linux_sigframe_init, |
| }; |
| |
| static LONGEST |
| bfin_linux_get_syscall_number (struct gdbarch *gdbarch, |
| thread_info *thread) |
| { |
| struct regcache *regcache = get_thread_regcache (thread); |
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
| /* The content of a register. */ |
| gdb_byte buf[4]; |
| /* The result. */ |
| LONGEST ret; |
| |
| /* Getting the system call number from the register. |
| When dealing with Blackfin architecture, this information |
| is stored at %p0 register. */ |
| regcache->cooked_read (BFIN_P0_REGNUM, buf); |
| |
| ret = extract_signed_integer (buf, 4, byte_order); |
| |
| return ret; |
| } |
| |
| static void |
| bfin_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) |
| { |
| linux_init_abi (info, gdbarch, 0); |
| |
| /* Set the sigtramp frame sniffer. */ |
| tramp_frame_prepend_unwinder (gdbarch, &bfin_linux_sigframe); |
| |
| /* Functions for 'catch syscall'. */ |
| set_xml_syscall_file_name (gdbarch, "syscalls/bfin-linux.xml"); |
| set_gdbarch_get_syscall_number (gdbarch, |
| bfin_linux_get_syscall_number); |
| } |
| |
| void _initialize_bfin_linux_tdep (); |
| void |
| _initialize_bfin_linux_tdep () |
| { |
| gdbarch_register_osabi (bfd_arch_bfin, 0, GDB_OSABI_LINUX, |
| bfin_linux_init_abi); |
| } |