text: /* Target-dependent code for Analog Devices Blackfin processor, for GDB.
  
     Copyright (C) 2005-2017 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, -1 },
    },
    bfin_linux_sigframe_init,
  };
  
  static LONGEST
  bfin_linux_get_syscall_number (struct gdbarch *gdbarch,
                                 ptid_t ptid)
  {
    struct regcache *regcache = get_thread_regcache (ptid);
    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 (regcache, 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);
  
    /* 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);
  }
  
  /* Provide a prototype to silence -Wmissing-prototypes.  */
  extern initialize_file_ftype _initialize_bfin_linux_tdep;
  
  void
  _initialize_bfin_linux_tdep (void)
  {
    gdbarch_register_osabi (bfd_arch_bfin, 0, GDB_OSABI_LINUX,
                            bfin_linux_init_abi);
  }
  