[0/2] C-SKY Port

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

[0/2] C-SKY Port

Hafiz Abid Qadeer
This patch series is a new GDB port for C-SKY ABI V2 processors. There
is support for bare-metal ELF and Linux target. This code is being
contributed jointly by C-SKY Microsystems and Mentor Graphics. C-SKY is
responsible for the technical content and has proposed Jiangshuai Li as
port maintainers. Mentor Graphics' role has been cleaning up the code
and bug-fixing. We have test both ELF and Linux target using QEMU and
test results look good.

The csky bunutils and gcc ports were submitted recently.
[binutils] https://sourceware.org/ml/binutils/2018-07/msg00306.html
[gcc] https://gcc.gnu.org/ml/gcc-patches/2018-07/msg01289.html

There are 2 patches in this series:

[1] CSKY port
[2] NEWS entry

Regards,
--
Hafiz Abid Qadeer
Mentor Embedded/CodeSourcery

Reply | Threaded
Open this post in threaded view
|

[1/2] C-SKY Port

Hafiz Abid Qadeer
Add support for new target 'csky'.

2018-07-25  Jiangshuai Li  <[hidden email]>
            Hafiz Abid Qadeer  <[hidden email]>
            Don Breazeal  <[hidden email]>

        * csky-linux-tdep.c: New file.
        * csky-tdep.c: Likewise.
        * csky-tdep.h: Likewise.
        * Makefile.in (ALL_TARGET_OBS): Add csky-linux-tdep.o and
        csky-tdep.o.
        (HFILES_NO_SRCDIR): Add csky-tdep.h.
        (ALLDEPFILES): Add csky-linux-tdep.c and csky-tdep.c
        * configure.tgt: Add csky support.
---
 gdb/Makefile.in       |    5 +
 gdb/configure.tgt     |   11 +
 gdb/csky-linux-tdep.c |  263 ++++++
 gdb/csky-tdep.c       | 2329
+++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/csky-tdep.h       |  355 ++++++++
 5 files changed, 2963 insertions(+)
 create mode 100644 gdb/csky-linux-tdep.c
 create mode 100644 gdb/csky-tdep.c
 create mode 100644 gdb/csky-tdep.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8c744d70c0..9eb420f250 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -688,6 +688,8 @@ ALL_TARGET_OBS = \
  bsd-uthread.o \
  cris-linux-tdep.o \
  cris-tdep.o \
+ csky-linux-tdep.o \
+ csky-tdep.o \
  dicos-tdep.o \
  fbsd-tdep.o \
  frv-linux-tdep.o \
@@ -1207,6 +1209,7 @@ HFILES_NO_SRCDIR = \
  completer.h \
  cp-abi.h \
  cp-support.h \
+ csky-tdep.h \
  ctf.h \
  d-lang.h \
  darwin-nat.h \
@@ -2207,6 +2210,8 @@ ALLDEPFILES = \
  bfin-tdep.c \
  bsd-kvm.c \
  bsd-uthread.c \
+ csky-linux-tdep.c \
+ csky-tdep.c \
  darwin-nat.c \
  dicos-tdep.c \
  fbsd-nat.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index f197160896..ae711d8bd9 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -206,6 +206,17 @@ cris*)
  gdb_target_obs="cris-tdep.o cris-linux-tdep.o linux-tdep.o solib-svr4.o"
  ;;

+csky*-linux*)
+ # Target: CSKY running GNU/Linux
+ gdb_target_obs="csky-tdep.o csky-linux-tdep.o glibc-tdep.o \
+ linux-tdep.o solib-svr4.o"
+ ;;
+
+csky*-*)
+ # Target: CSKY bare metal
+ gdb_target_obs="csky-tdep.o"
+ ;;
+
 frv-*-*)
  # Target: Fujitsu FRV processor
  gdb_target_obs="frv-tdep.o frv-linux-tdep.o linux-tdep.o solib-frv.o"
diff --git a/gdb/csky-linux-tdep.c b/gdb/csky-linux-tdep.c
new file mode 100644
index 0000000000..9e3ec393c8
--- /dev/null
+++ b/gdb/csky-linux-tdep.c
@@ -0,0 +1,263 @@
+/* Target-dependent code for GNU/Linux on CSKY.
+
+   Copyright (C) 2012-2018 Free Software Foundation, Inc.
+
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   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 "osabi.h"
+#include "glibc-tdep.h"
+#include "linux-tdep.h"
+#include "gdbarch.h"
+#include "solib-svr4.h"
+#include "regset.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+#include "csky-tdep.h"
+
+/* Functions, definitions, and data structures for C-Sky core file
debug.  */
+
+/* General regset pc, r1, r0, psr, r2-r31 for CK810.  */
+#define SIZEOF_CSKY_GREGSET 34*4
+/* Float regset fesr fsr fr0-fr31 for CK810.  */
+#define SIZEOF_CSKY_FREGSET 34*4
+
+/* Offset mapping table from core_section to regcache of general
+   registers for ck810.  */
+static const int csky_gregset_offset[] =
+{
+  72,  1,  0, 89,  2,  /* pc, r1, r0, psr, r2.  */
+   3,  4,  5,  6,  7,  /* r3 ~ r32.  */
+   8,  9, 10, 11, 12,
+  13, 14, 15, 16, 17,
+  18, 19, 20, 21, 22,
+  23, 24, 25, 26, 27,
+  28, 29, 30, 31
+};
+
+/* Offset mapping table from core_section to regcache of float
+   registers for ck810.  */
+
+static const int csky_fregset_offset[] =
+{
+  122, 123, 40, 41, 42,     /* fcr, fesr, fr0 ~ fr2.  */
+   43,  44, 45, 46, 47,     /* fr3 ~ fr15.  */
+   48,  49, 50, 51, 52,
+   53,  54, 55
+};
+
+/* Implement the supply_regset hook for GP registers in core files.  */
+
+static void
+csky_supply_gregset (const struct regset *regset,
+     struct regcache *regcache, int regnum,
+     const void *regs, size_t len)
+{
+  int i, gregset_num;
+  const gdb_byte *gregs = (const gdb_byte *) regs ;
+
+  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
+  gregset_num = ARRAY_SIZE (csky_gregset_offset);
+
+  for (i = 0; i < gregset_num; i++)
+    {
+      if ((regnum == csky_gregset_offset[i] || regnum == -1)
+  && csky_gregset_offset[i] != -1)
+ regcache->raw_supply (csky_gregset_offset[i], gregs + 4 * i);
+    }
+}
+
+/* Implement the collect_regset hook for GP registers in core files.  */
+
+static void
+csky_collect_gregset (const struct regset *regset,
+      const struct regcache *regcache,
+      int regnum, void *gregs_buf, size_t len)
+{
+  int regno, gregset_num;
+  gdb_byte *gregs = (gdb_byte *) gregs_buf ;
+
+  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
+  gregset_num = ARRAY_SIZE (csky_gregset_offset);
+
+  for (regno = 0; regno < gregset_num; regno++)
+    {
+      if ((regnum == csky_gregset_offset[regno] || regnum == -1)
+  && csky_gregset_offset[regno] != -1)
+ regcache->raw_collect (regno,
+       gregs + 4 + csky_gregset_offset[regno]);
+    }
+}
+
+/* Implement the supply_regset hook for FP registers in core files.  */
+
+void
+csky_supply_fregset (const struct regset *regset,
+     struct regcache *regcache, int regnum,
+     const void *regs, size_t len)
+{
+  int i;
+  int offset = 0;
+  struct gdbarch *gdbarch = regcache->arch ();
+  const gdb_byte *fregs = (const gdb_byte *) regs;
+  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
+
+  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
+  for (i = 0; i < fregset_num; i++)
+    {
+      if ((regnum == csky_fregset_offset[i] || regnum == -1)
+  && csky_fregset_offset[i] != -1)
+ {
+  int num = csky_fregset_offset[i];
+  offset += register_size (gdbarch, num);
+  regcache->raw_supply (csky_fregset_offset[i], fregs + offset);
+ }
+    }
+}
+
+/* Implement the collect_regset hook for FP registers in core files.  */
+
+static void
+csky_collect_fregset (const struct regset *regset,
+      const struct regcache *regcache,
+      int regnum, void *fregs_buf, size_t len)
+{
+  int regno;
+  struct gdbarch *gdbarch = regcache->arch ();
+  gdb_byte *fregs = (gdb_byte *) fregs_buf ;
+  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
+  int offset = 0;
+
+  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
+  for (regno = 0; regno < fregset_num; regno++)
+    {
+      if ((regnum == csky_fregset_offset[regno] || regnum == -1)
+  && csky_fregset_offset[regno] != -1)
+ {
+  offset += register_size (gdbarch, csky_fregset_offset[regno]);
+  regcache->raw_collect (regno, fregs + offset);
+ }
+    }
+}
+
+static const struct regset csky_regset_general =
+{
+  NULL,
+  csky_supply_gregset,
+  csky_collect_gregset
+};
+
+static const struct regset csky_regset_float =
+{
+  NULL,
+  csky_supply_fregset,
+  csky_collect_fregset
+};
+
+/* Iterate over core file register note sections.  */
+
+static void
+csky_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
+{
+  cb (".reg", sizeof (csky_gregset_offset), &csky_regset_general,
+      NULL, cb_data);
+  cb (".reg2", sizeof (csky_fregset_offset), &csky_regset_float,
+      NULL, cb_data);
+}
+
+static void
+csky_linux_rt_sigreturn_init (const struct tramp_frame *self,
+      struct frame_info *this_frame,
+      struct trad_frame_cache *this_cache,
+      CORE_ADDR func)
+{
+  int i;
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, 14);
+
+  CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE
+   + CSKY_UCONTEXT_SIGCONTEXT
+   + CSKY_SIGCONTEXT_SC_USP
+   + CSKY_SIGCONTEXT_SC_A0;
+
+  /* Set addrs of R0 ~ R13.  */
+  for (i = 0; i < 14; i++)
+   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
+
+  /* Set addrs of SP(R14) and R15.  */
+  trad_frame_set_reg_addr (this_cache, 14, base - 4);
+  trad_frame_set_reg_addr (this_cache, 15, base + 4 * 14);
+
+  /* Set addrs of R16 ~ R31.  */
+  for (i = 15; i < 31; i++)
+   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
+
+  /* Set addrs of PSR and PC.  */
+  trad_frame_set_reg_addr (this_cache, 89, base + 4 * 33);
+  trad_frame_set_reg_addr (this_cache, 72, base + 4 * 34);
+
+  trad_frame_set_id (this_cache, frame_id_build (sp, func));
+}
+
+static struct tramp_frame
+csky_linux_rt_sigreturn_tramp_frame = {
+  SIGTRAMP_FRAME,
+  4,
+  {
+    { CSKY_MOVI_R7_173, -1 },
+    { CSKY_TRAP_0, -1 },
+    { TRAMP_SENTINEL_INSN }
+  },
+  csky_linux_rt_sigreturn_init
+};
+
+/* Hook function for gdbarch_register_osabi.  */
+
+static void
+csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  linux_init_abi (info, gdbarch);
+
+  /* Shared library handling.  */
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+
+  /* Enable TLS support.  */
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+     svr4_fetch_objfile_link_map);
+
+  /* Core file support.  */
+  set_gdbarch_iterate_over_regset_sections (
+    gdbarch, csky_linux_iterate_over_regset_sections);
+
+  /* Append tramp frame unwinder for SIGNAL.  */
+
+  tramp_frame_prepend_unwinder (gdbarch,
+ &csky_linux_rt_sigreturn_tramp_frame);
+}
+
+void
+_initialize_csky_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_csky, 0, GDB_OSABI_LINUX,
+  csky_linux_init_abi);
+}
diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
new file mode 100644
index 0000000000..5e41c62205
--- /dev/null
+++ b/gdb/csky-tdep.c
@@ -0,0 +1,2329 @@
+/* Target-dependent code for the CSKY architecture, for GDB.
+
+   Copyright (C) 2010-2018 Free Software Foundation, Inc.
+
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   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 "gdb_assert.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "block.h"
+#include "reggroups.h"
+#include "elf/csky.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "dis-asm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "infcall.h"
+#include "floatformat.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "dwarf2-frame.h"
+#include "user-regs.h"
+#include "valprint.h"
+#include "reggroups.h"
+#include "csky-tdep.h"
+#include "regset.h"
+#include "block.h"
+#include "opcode/csky.h"
+#include <algorithm>
+
+/* Control debugging information emitted in this file.  */
+static int csky_debug = 0;
+
+static struct reggroup *cr_reggroup;
+static struct reggroup *fr_reggroup;
+static struct reggroup *vr_reggroup;
+static struct reggroup *mmu_reggroup;
+static struct reggroup *prof_reggroup;
+
+/* Convenience function to print debug messages in prologue analysis.  */
+
+static void
+print_savedreg_msg (int regno, int offsets[], bool print_continuing)
+{
+  fprintf_unfiltered (gdb_stdlog, "csky: r%d saved at offset 0x%x\n",
+      regno, offsets[regno]);
+  if (print_continuing)
+    fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+}
+
+/*  Check whether the instruction at ADDR is 16-bit or not.  */
+
+static int
+csky_pc_is_csky16 (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_byte target_mem[2];
+  int status;
+  unsigned int insn;
+  int ret = 1;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  status = target_read_memory (addr, target_mem, 2);
+  /* Assume a 16-bit instruction if we can't read memory.  */
+  if (status)
+    return 1;
+
+  /* Get instruction from memory.  */
+  insn = extract_unsigned_integer (target_mem, 2, byte_order);
+  if ((insn & CSKY_32_INSN_MASK) == CSKY_32_INSN_MASK)
+    ret = 0;
+  else if (insn == CSKY_BKPT_INSN)
+    {
+      /* Check for 32-bit bkpt instruction which is all 0.  */
+      status = target_read_memory (addr + 2, target_mem, 2);
+      if (status)
+ return 1;
+
+      insn = extract_unsigned_integer (target_mem, 2, byte_order);
+      if (insn == CSKY_BKPT_INSN)
+ ret = 0;
+    }
+  return ret;
+}
+
+/* Get one instruction at ADDR and store it in INSN.  Return 2 for
+   a 16-bit instruction or 4 for a 32-bit instruction.  */
+
+static int
+csky_get_insn (struct gdbarch *gdbarch, CORE_ADDR addr, unsigned int *insn)
+{
+  gdb_byte target_mem[2];
+  unsigned int insn_type;
+  int status;
+  int insn_len = 2;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  status = target_read_memory (addr, target_mem, 2);
+  if (status)
+    memory_error (TARGET_XFER_E_IO, addr);
+
+  insn_type = extract_unsigned_integer (target_mem, 2, byte_order);
+  if (CSKY_32_INSN_MASK == (insn_type & CSKY_32_INSN_MASK))
+    {
+      status = target_read_memory (addr + 2, target_mem, 2);
+      if (status)
+ memory_error (TARGET_XFER_E_IO, addr);
+      insn_type = ((insn_type << 16)
+   | extract_unsigned_integer (target_mem, 2, byte_order));
+      insn_len = 4;
+    }
+  *insn = insn_type;
+  return insn_len;
+}
+
+/* Implement the read_pc gdbarch method.  */
+
+static CORE_ADDR
+csky_read_pc (readable_regcache *regcache)
+{
+  ULONGEST pc;
+  regcache->cooked_read (CSKY_PC_REGNUM, &pc);
+  return pc;
+}
+
+/* Implement the write_pc gdbarch method.  */
+
+static void
+csky_write_pc (regcache *regcache, CORE_ADDR val)
+{
+  regcache_cooked_write_unsigned (regcache, CSKY_PC_REGNUM, val);
+}
+
+/* Implement the unwind_sp gdbarch method.  */
+
+static CORE_ADDR
+csky_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, CSKY_SP_REGNUM);
+}
+
+/* C-Sky ABI register names.  */
+
+static const char *csky_register_names[] =
+{
+  /* General registers 0 - 31.  */
+  "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+  "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+
+  /* DSP hilo registers 36 and 37.  */
+  "",      "",    "",     "",     "hi",    "lo",   "",    "",
+
+  /* FPU/VPU general registers 40 - 71.  */
+  "fr0", "fr1", "fr2",  "fr3",  "fr4",  "fr5",  "fr6",  "fr7",
+  "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+  "vr0", "vr1", "vr2",  "vr3",  "vr4",  "vr5",  "vr6",  "vr7",
+  "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15",
+
+  /* Program counter 72.  */
+  "pc",
+
+  /* Optional registers (ar) 73 - 88.  */
+  "ar0", "ar1", "ar2",  "ar3",  "ar4",  "ar5",  "ar6",  "ar7",
+  "ar8", "ar9", "ar10", "ar11", "ar12", "ar13", "ar14", "ar15",
+
+  /* Control registers (cr) 89 - 119.  */
+  "psr",  "vbr",  "epsr", "fpsr", "epc",  "fpc",  "ss0",  "ss1",
+  "ss2",  "ss3",  "ss4",  "gcr",  "gsr",  "cr13", "cr14", "cr15",
+  "cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
+  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
+
+  /* FPU/VPU control registers 121 ~ 123.  */
+  /* User sp 127.  */
+  "fid", "fcr", "fesr", "", "", "", "usp",
+
+  /* MMU control registers: 128 - 136.  */
+  "mcr0", "mcr2", "mcr3", "mcr4", "mcr6", "mcr8", "mcr29", "mcr30",
+  "mcr31", "", "", "",
+
+  /* Profiling control registers 140 - 143.  */
+  /* Profiling software general registers 144 - 157.  */
+  "profcr0",  "profcr1",  "profcr2",  "profcr3",  "profsgr0",  "profsgr1",
+  "profsgr2", "profsgr3", "profsgr4", "profsgr5", "profsgr6",  "profsgr7",
+  "profsgr8", "profsgr9", "profsgr10","profsgr11","profsgr12", "profsgr13",
+  "", "",
+
+  /* Profiling architecture general registers 160 - 174.  */
+  "profagr0", "profagr1", "profagr2", "profagr3", "profagr4", "profagr5",
+  "profagr6", "profagr7", "profagr8", "profagr9", "profagr10","profagr11",
+  "profagr12","profagr13","profagr14", "",
+
+  /* Profiling extension general registers 176 - 188.  */
+  "profxgr0", "profxgr1", "profxgr2", "profxgr3", "profxgr4", "profxgr5",
+  "profxgr6", "profxgr7", "profxgr8", "profxgr9", "profxgr10","profxgr11",
+  "profxgr12",
+
+  /* Control registers in bank1.  */
+  "", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", "",
+  "cp1cr16", "cp1cr17", "cp1cr18", "cp1cr19", "cp1cr20", "", "", "",
+  "", "", "", "", "", "", "", "",
+
+  /* Control registers in bank3 (ICE).  */
+  "sepsr", "sevbr", "seepsr", "", "seepc", "", "nsssp", "seusp",
+  "sedcr", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", ""
+};
+
+/* Implement the register_name gdbarch method.  */
+
+static const char *
+csky_register_name (struct gdbarch *gdbarch, int reg_nr)
+{
+  int csky_total_regnum;
+
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return tdesc_register_name (gdbarch, reg_nr);
+
+  if (reg_nr < 0)
+    return NULL;
+
+  if (reg_nr >= gdbarch_num_regs (gdbarch))
+    return NULL;
+
+  return csky_register_names[reg_nr];
+}
+
+/* Construct vector type for vrx registers.  */
+
+static struct type *
+csky_vector_type (struct gdbarch *gdbarch)
+{
+  const struct builtin_type *bt = builtin_type (gdbarch);
+
+  struct type *t;
+
+  t = arch_composite_type (gdbarch, "__gdb_builtin_type_vec128i",
+   TYPE_CODE_UNION);
+
+  append_composite_type_field (t, "u32",
+       init_vector_type (bt->builtin_int32, 4));
+  append_composite_type_field (t, "u16",
+       init_vector_type (bt->builtin_int16, 8));
+  append_composite_type_field (t, "u8",
+       init_vector_type (bt->builtin_int8, 16));
+
+  TYPE_VECTOR (t) = 1;
+  TYPE_NAME (t) = "builtin_type_vec128i";
+
+  return t;
+}
+
+/* Return the GDB type object for the "standard" data type
+   of data in register N.  */
+
+static struct type *
+csky_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+  int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
+
+  /* PC, EPC, FPC is a text pointer.  */
+  if ((reg_nr == CSKY_PC_REGNUM)  || (reg_nr == CSKY_EPC_REGNUM)
+      || (reg_nr == CSKY_FPC_REGNUM))
+    return builtin_type (gdbarch)->builtin_func_ptr;
+
+  /* VBR is a data pointer.  */
+  if (reg_nr == CSKY_VBR_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+
+  /* Float register has 64 bits, and only in ck810.  */
+  if ((reg_nr >=CSKY_FR0_REGNUM) && (reg_nr <= CSKY_FR0_REGNUM + 15))
+      return arch_float_type (gdbarch, 64, "builtin_type_csky_ext",
+      floatformats_ieee_double);
+
+  /* Vector register has 128 bits, and only in ck810.  */
+  if ((reg_nr >= CSKY_VR0_REGNUM) && (reg_nr <= CSKY_VR0_REGNUM + 15))
+    return csky_vector_type (gdbarch);
+
+  /* Profiling general register has 48 bits, we use 64bit.  */
+  if ((reg_nr >= CSKY_PROFGR_REGNUM) && (reg_nr <= CSKY_PROFGR_REGNUM +
44))
+    return builtin_type (gdbarch)->builtin_uint64;
+
+  if (reg_nr == CSKY_SP_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+
+  /* Others are 32 bits.  */
+  return builtin_type (gdbarch)->builtin_int32;
+}
+
+/* Data structure to marshall items in a dummy stack frame when
+   calling a function in the inferior.  */
+
+struct stack_item
+{
+  int len;
+  struct stack_item *prev;
+  void *data;
+};
+
+/* Push an item onto our dummy stack.  */
+
+static struct stack_item *
+push_stack_item (struct stack_item *prev, const void *contents, int len)
+{
+  struct stack_item *si;
+  si = (struct stack_item *) xmalloc (sizeof (struct stack_item));
+  si->data = xmalloc (len);
+  si->len = len;
+  si->prev = prev;
+  memcpy (si->data, contents, len);
+  return si;
+}
+
+/* Pop an item off of our dummy stack.  */
+
+static struct stack_item *
+pop_stack_item (struct stack_item *si)
+{
+  struct stack_item *dead = si;
+  si = si->prev;
+  xfree (dead->data);
+  xfree (dead);
+  return si;
+}
+
+/* Implement the push_dummy_call gdbarch method.  */
+
+static CORE_ADDR
+csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+      struct regcache *regcache, CORE_ADDR bp_addr,
+      int nargs, struct value **args, CORE_ADDR sp,
+      int struct_return, CORE_ADDR struct_addr)
+{
+  int argnum;
+  int argreg = CSKY_ABI_A0_REGNUM;
+  int last_arg_regnum = CSKY_ABI_LAST_ARG_REGNUM;
+  int need_dummy_stack = 0;
+  struct stack_item *si = NULL;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  /* Set the return address.  For CSKY, the return breakpoint is
+     always at BP_ADDR.  */
+  regcache_cooked_write_unsigned (regcache, CSKY_LR_REGNUM, bp_addr);
+
+  /* The struct_return pointer occupies the first parameter
+     passing register.  */
+  if (struct_return)
+    {
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: struct return in %s = %s\n",
+      gdbarch_register_name (gdbarch, argreg),
+      paddress (gdbarch, struct_addr));
+ }
+      regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
+      argreg++;
+    }
+
+  /* Put parameters into argument registers in REGCACHE.
+     In ABI argument registers are r0 through r3.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      int len;
+      struct type *arg_type;
+      const bfd_byte *val;
+
+      arg_type = check_typedef (value_type (args[argnum]));
+      len = TYPE_LENGTH (arg_type);
+      val = value_contents (args[argnum]);
+
+      /* Copy the argument to argument registers or the dummy stack.
+ Large arguments are split between registers and stack.
+
+ If len < 4, there is no need to worry about endianness since
+ the arguments will always be stored in the low address.  */
+      if (len < 4)
+ {
+  CORE_ADDR regval
+    = extract_unsigned_integer (val, len, byte_order);
+  regcache_cooked_write_unsigned (regcache, argreg, regval);
+  argreg++;
+ }
+      else
+ {
+  while (len > 0)
+    {
+      int partial_len = len < 4 ? len : 4;
+      if (argreg <= last_arg_regnum)
+ {
+  /* The argument is passed in an argument register.  */
+  CORE_ADDR regval
+    = extract_unsigned_integer (val, partial_len,
+ byte_order);
+  if (byte_order == BFD_ENDIAN_BIG)
+    regval <<= (4 - partial_len) * 8;
+
+  /* Put regval into register in REGCACHE.  */
+  regcache_cooked_write_unsigned (regcache, argreg,
+  regval);
+  argreg++;
+ }
+      else
+ {
+  /* The argument should be pushed onto the dummy stack.  */
+  si = push_stack_item (si, val, 4);
+  need_dummy_stack += 4;
+ }
+      len -= partial_len;
+      val += partial_len;
+    }
+ }
+    }
+
+  /* Transfer the dummy stack frame to the target.  */
+  while (si)
+    {
+      sp -= si->len;
+      write_memory (sp, (const bfd_byte *) si->data, si->len);
+      si = pop_stack_item (si);
+    }
+
+  /* Finally, update the SP register.  */
+  regcache_cooked_write_unsigned (regcache, CSKY_SP_REGNUM, sp);
+  return sp;
+}
+
+/* Implement the return_value gdbarch method.  */
+
+static enum return_value_convention
+csky_return_value (struct gdbarch *gdbarch, struct value *function,
+   struct type *valtype, struct regcache *regcache,
+   gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  CORE_ADDR regval;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int len = TYPE_LENGTH (valtype);
+  unsigned int ret_regnum = CSKY_RET_REGNUM;
+
+  /* Csky abi specifies that return values larger than 8 bytes
+     are put on the stack.  */
+  if (len > 8)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+  else
+    {
+      if (readbuf != NULL)
+ {
+  ULONGEST tmp;
+  /* By using store_unsigned_integer we avoid having to do
+     anything special for small big-endian values.  */
+  regcache->cooked_read (ret_regnum, &tmp);
+  store_unsigned_integer (readbuf, (len > 4 ? 4 : len),
+  byte_order, tmp);
+  if (len > 4)
+    {
+      regcache->cooked_read (ret_regnum + 1, &tmp);
+      store_unsigned_integer (readbuf + 4,  4, byte_order, tmp);
+    }
+ }
+      if (writebuf != NULL)
+ {
+  regval = extract_unsigned_integer (writebuf, len > 4 ? 4 : len,
+     byte_order);
+  regcache_cooked_write_unsigned (regcache, ret_regnum, regval);
+  if (len > 4)
+    {
+      regval = extract_unsigned_integer ((gdb_byte *) writebuf + 4,
+ 4, byte_order);
+      regcache_cooked_write_unsigned (regcache, ret_regnum + 1,
+      regval);
+    }
+
+ }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Implement the frame_align gdbarch method.
+
+   Adjust the address downward (direction of stack growth) so that it
+   is correctly aligned for a new stack frame.  */
+
+static CORE_ADDR
+csky_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 4);
+}
+
+/* Unwind cache used for gdbarch fallback unwinder.  */
+
+struct csky_unwind_cache
+{
+  /* The stack pointer at the time this frame was created; i.e. the
+     caller's stack pointer when this function was called.  It is used
+     to identify this frame.  */
+  CORE_ADDR prev_sp;
+
+  /* The frame base for this frame is just prev_sp - frame size.
+     FRAMESIZE is the distance from the frame pointer to the
+     initial stack pointer.  */
+  int framesize;
+
+  /* The register used to hold the frame pointer for this frame.  */
+  int framereg;
+
+  /* Saved register offsets.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Do prologue analysis, returning the PC of the first instruction
+   after the function prologue.  */
+
+static CORE_ADDR
+csky_analyze_prologue (struct gdbarch *gdbarch,
+       CORE_ADDR start_pc,
+       CORE_ADDR limit_pc,
+       CORE_ADDR end_pc,
+       struct frame_info *this_frame,
+       struct csky_unwind_cache *this_cache,
+       lr_type_t lr_type)
+{
+  CORE_ADDR addr;
+  CORE_ADDR sp;
+  CORE_ADDR stack_size;
+  unsigned int insn, rn;
+  int status;
+  int flags;
+  int framesize = 0;
+  int stacksize = 0;
+  int register_offsets[CSKY_NUM_GREGS_SAVED_GREGS];
+  int insn_len;
+  /* For adjusting fp.  */
+  int is_fp_saved = 0;
+  int adjust_fp = 0;
+
+  /* REGISTER_OFFSETS will contain offsets from the top of the frame
+     (NOT the frame pointer) for the various saved registers, or -1
+     if the register is not saved.  */
+  for (rn = 0; rn < CSKY_NUM_GREGS_SAVED_GREGS; rn++)
+    register_offsets[rn] = -1;
+
+  /* Analyze the prologue.  Things we determine from analyzing the
+     prologue include the size of the frame and which registers are
+     saved (and where).  */
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: Scanning prologue: start_pc = 0x%x,"
+  "limit_pc = 0x%x\n", (unsigned int) start_pc,
+  (unsigned int) limit_pc);
+    }
+
+  /* Default to 16 bit instruction.  */
+  insn_len = 2;
+  stacksize = 0;
+  for (addr = start_pc; addr < limit_pc; addr += insn_len)
+    {
+      /* Get next insn.  */
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+
+      /* Check if 32 bit.  */
+      if (insn_len == 4)
+ {
+  /* subi32 sp,sp oimm12.  */
+  if (CSKY_32_IS_SUBI0 (insn))
+    {
+      /* Got oimm12.  */
+      int offset = CSKY_32_SUBI_IMM (insn);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: got subi sp,%d; continuing\n",
+      offset);
+ }
+      stacksize += offset;
+      continue;
+    }
+  /* stm32 ry-rz,(sp).  */
+  else if (CSKY_32_IS_STMx0 (insn))
+    {
+      /* Spill register(s).  */
+      int start_register;
+      int reg_count;
+      int offset;
+
+      /* BIG WARNING! The CKCore ABI does not restrict functions
+ to taking only one stack allocation.  Therefore, when
+ we save a register, we record the offset of where it was
+ saved relative to the current stacksize.  This will
+ then give an offset from the SP upon entry to our
+ function.  Remember, stacksize is NOT constant until
+ we're done scanning the prologue.  */
+      start_register = CSKY_32_STM_VAL_REGNUM (insn);
+      reg_count = CSKY_32_STM_SIZE (insn);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: got stm r%d-r%d,(sp)\n",
+      start_register,
+      start_register + reg_count);
+ }
+
+      for (rn = start_register, offset = 0;
+   rn <= start_register + reg_count;
+   rn++, offset += 4)
+ {
+  register_offsets[rn] = stacksize - offset;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: r%d saved at 0x%x"
+  " (offset %d)\n",
+  rn, register_offsets[rn],
+  offset);
+    }
+ }
+      if (csky_debug)
+ fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+      continue;
+    }
+  /* stw ry,(sp,disp).  */
+  else if (CSKY_32_IS_STWx0 (insn))
+    {
+      /* Spill register: see note for IS_STM above.  */
+      int disp;
+
+      rn = CSKY_32_ST_VAL_REGNUM (insn);
+      disp = CSKY_32_ST_OFFSET (insn);
+      register_offsets[rn] = stacksize - disp;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  else if (CSKY_32_IS_MOV_FP_SP (insn))
+    {
+      /* SP is saved to FP reg, means code afer prologue may
+ modify SP.  */
+      is_fp_saved = 1;
+      adjust_fp = stacksize;
+      continue;
+    }
+  else if (CSKY_32_IS_MFCR_EPSR (insn))
+    {
+      unsigned int insn2;
+      addr += 4;
+      int mfcr_regnum = insn & 0x1f;
+      insn_len = csky_get_insn (gdbarch, addr, &insn2);
+      if (insn_len == 2)
+ {
+  int stw_regnum = (insn2 >> 5) & 0x7;
+  if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_EPSR_REGNUM.  */
+      rn  = CSKY_NUM_GREGS;
+      offset = CSKY_16_STWx0_OFFSET (insn2);
+      register_offsets[rn] = stacksize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+      else
+ {
+  /* INSN_LEN == 4.  */
+  int stw_regnum = (insn2 >> 21) & 0x1f;
+  if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_EPSR_REGNUM.  */
+      rn  = CSKY_NUM_GREGS;
+      offset = CSKY_32_ST_OFFSET (insn2);
+      register_offsets[rn] = framesize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+    }
+  else if (CSKY_32_IS_MFCR_FPSR (insn))
+    {
+      unsigned int insn2;
+      addr += 4;
+      int mfcr_regnum = insn & 0x1f;
+      insn_len = csky_get_insn (gdbarch, addr, &insn2);
+      if (insn_len == 2)
+ {
+  int stw_regnum = (insn2 >> 5) & 0x7;
+  if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum
+ == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_FPSR_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 1;
+      offset = CSKY_16_STWx0_OFFSET (insn2);
+      register_offsets[rn] = stacksize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+      else
+ {
+  /* INSN_LEN == 4.  */
+  int stw_regnum = (insn2 >> 21) & 0x1f;
+  if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_FPSR_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 1;
+      offset = CSKY_32_ST_OFFSET (insn2);
+      register_offsets[rn] = framesize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+    }
+  else if (CSKY_32_IS_MFCR_EPC (insn))
+    {
+      unsigned int insn2;
+      addr += 4;
+      int mfcr_regnum = insn & 0x1f;
+      insn_len = csky_get_insn (gdbarch, addr, &insn2);
+      if (insn_len == 2)
+ {
+  int stw_regnum = (insn2 >> 5) & 0x7;
+  if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_EPC_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 2;
+      offset = CSKY_16_STWx0_OFFSET (insn2);
+      register_offsets[rn] = stacksize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+      else
+ {
+  /* INSN_LEN == 4.  */
+  int stw_regnum = (insn2 >> 21) & 0x1f;
+  if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_EPC_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 2;
+      offset = CSKY_32_ST_OFFSET (insn2);
+      register_offsets[rn] = framesize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+    }
+  else if (CSKY_32_IS_MFCR_FPC (insn))
+    {
+      unsigned int insn2;
+      addr += 4;
+      int mfcr_regnum = insn & 0x1f;
+      insn_len = csky_get_insn (gdbarch, addr, &insn2);
+      if (insn_len == 2)
+ {
+  int stw_regnum = (insn2 >> 5) & 0x7;
+  if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_FPC_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 3;
+      offset = CSKY_16_STWx0_OFFSET (insn2);
+      register_offsets[rn] = stacksize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+      else
+ {
+  /* INSN_LEN == 4.  */
+  int stw_regnum = (insn2 >> 21) & 0x1f;
+  if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_FPC_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 3;
+      offset = CSKY_32_ST_OFFSET (insn2);
+      register_offsets[rn] = framesize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+    }
+  else if (CSKY_32_IS_PUSH (insn))
+    {
+      /* Push for 32_bit.  */
+      int offset = 0;
+      if (CSKY_32_IS_PUSH_R29 (insn))
+ {
+  stacksize += 4;
+  register_offsets[29] = stacksize;
+  if (csky_debug)
+    print_savedreg_msg (29, register_offsets, false);
+  offset += 4;
+ }
+      if (CSKY_32_PUSH_LIST2 (insn))
+ {
+  int num = CSKY_32_PUSH_LIST2 (insn);
+  int tmp = 0;
+  stacksize += num * 4;
+  offset += num * 4;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: push regs_array: r16-r%d\n",
+  16 + num - 1);
+    }
+  for (rn = 16; rn <= 16 + num - 1; rn++)
+    {
+       register_offsets[rn] = stacksize - tmp;
+       if (csky_debug)
+ {
+   fprintf_unfiltered (gdb_stdlog,
+       "csky: r%d saved at 0x%x"
+       " (offset %d)\n", rn,
+       register_offsets[rn], tmp);
+ }
+       tmp += 4;
+    }
+ }
+      if (CSKY_32_IS_PUSH_R15 (insn))
+ {
+  stacksize += 4;
+  register_offsets[15] = stacksize;
+  if (csky_debug)
+    print_savedreg_msg (15, register_offsets, false);
+  offset += 4;
+ }
+      if (CSKY_32_PUSH_LIST1 (insn))
+ {
+  int num = CSKY_32_PUSH_LIST1 (insn);
+  int tmp = 0;
+  stacksize += num * 4;
+  offset += num * 4;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: push regs_array: r4-r%d\n",
+  4 + num - 1);
+    }
+  for (rn = 4; rn <= 4 + num - 1; rn++)
+    {
+       register_offsets[rn] = stacksize - tmp;
+       if (csky_debug)
+ {
+   fprintf_unfiltered (gdb_stdlog,
+       "csky: r%d saved at 0x%x"
+       " (offset %d)\n", rn,
+       register_offsets[rn], tmp);
+ }
+ tmp += 4;
+    }
+ }
+
+      framesize = stacksize;
+      if (csky_debug)
+ fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+      continue;
+    }
+  else if (CSKY_32_IS_LRW4 (insn) || CSKY_32_IS_MOVI4 (insn)
+   || CSKY_32_IS_MOVIH4 (insn) || CSKY_32_IS_BMASKI4 (insn))
+    {
+      int adjust = 0;
+      int offset = 0;
+      unsigned int insn2;
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: looking at large frame\n");
+ }
+      if (CSKY_32_IS_LRW4 (insn))
+ {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int literal_addr = (addr + ((insn & 0xffff) << 2))
+     & 0xfffffffc;
+  adjust = read_memory_unsigned_integer (literal_addr, 4,
+ byte_order);
+ }
+      else if (CSKY_32_IS_MOVI4 (insn))
+ adjust = (insn  & 0xffff);
+      else if (CSKY_32_IS_MOVIH4 (insn))
+ adjust = (insn & 0xffff) << 16;
+      else
+ {
+  /* CSKY_32_IS_BMASKI4 (insn).  */
+  adjust = (1 << (((insn & 0x3e00000) >> 21) + 1)) - 1;
+ }
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: base stacksize=0x%x\n", adjust);
+
+  /* May have zero or more insns which modify r4.  */
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: looking for r4 adjusters...\n");
+ }
+
+      offset = 4;
+      insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+      while (CSKY_IS_R4_ADJUSTER (insn2))
+ {
+  if (CSKY_32_IS_ADDI4 (insn2))
+    {
+      int imm = (insn2 & 0xfff) + 1;
+      adjust += imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: addi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_SUBI4 (insn2))
+    {
+      int imm = (insn2 & 0xfff) + 1;
+      adjust -= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: subi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_NOR4 (insn2))
+    {
+      adjust = ~adjust;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: nor r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_32_IS_ROTLI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      int temp = adjust >> (32 - imm);
+      adjust <<= imm;
+      adjust |= temp;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: rotli r4,r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_LISI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust <<= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: lsli r4,r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_BSETI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust |= (1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bseti r4,r4 %d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_BCLRI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust &= ~(1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bclri r4,r4 %d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_IXH4 (insn2))
+    {
+      adjust *= 3;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: ixh r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_32_IS_IXW4 (insn2))
+    {
+      adjust *= 5;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: ixw r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_16_IS_ADDI4 (insn2))
+    {
+      int imm = (insn2 & 0xff) + 1;
+      adjust += imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: addi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_SUBI4 (insn2))
+    {
+      int imm = (insn2 & 0xff) + 1;
+      adjust -= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: subi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_NOR4 (insn2))
+    {
+      adjust = ~adjust;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: nor r4,r4\n");
+ }
+    }
+  else if (CSKY_16_IS_BSETI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust |= (1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bseti r4, %d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_BCLRI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust &= ~(1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bclri r4, %d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_LSLI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust <<= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: lsli r4,r4, %d\n", imm);
+ }
+    }
+
+  offset += insn_len;
+  insn_len =  csky_get_insn (gdbarch, addr + offset, &insn2);
+ };
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog, "csky: done looking for"
+      " r4 adjusters\n");
+ }
+
+      /* If the next insn adjusts the stack pointer, we keep
+ everything; if not, we scrap it and we've found the
+ end of the prologue.  */
+      if (CSKY_IS_SUBU4 (insn2))
+ {
+  addr += offset;
+  stacksize += adjust;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: found stack adjustment of"
+  " 0x%x bytes.\n", adjust);
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: skipping to new address "
+  "0x%lx\n", addr);
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: continuing\n");
+    }
+  continue;
+ }
+
+      /* None of these instructions are prologue, so don't touch
+ anything.  */
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: no subu sp,sp,r4; NOT altering"
+      " stacksize.\n");
+ }
+      break;
+    }
+ }
+      else
+ {
+  /* insn_len != 4.  */
+
+  /* subi.sp sp,disp.  */
+  if (CSKY_16_IS_SUBI0 (insn))
+    {
+      int offset = CSKY_16_SUBI_IMM (insn);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: got subi r0,%d; continuing\n",
+      offset);
+ }
+      stacksize += offset;
+      continue;
+    }
+  /* stw.16 rz,(sp,disp).  */
+  else if (CSKY_16_IS_STWx0 (insn))
+    {
+      /* Spill register: see note for IS_STM above.  */
+      int disp;
+
+      rn = CSKY_16_ST_VAL_REGNUM (insn);
+      disp = CSKY_16_ST_OFFSET (insn);
+      register_offsets[rn] = stacksize - disp;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  else if (CSKY_16_IS_MOV_FP_SP (insn))
+    {
+      /* SP is saved to FP reg, means prologue may modify SP.  */
+      is_fp_saved = 1;
+      adjust_fp = stacksize;
+      continue;
+    }
+  else if (CSKY_16_IS_PUSH (insn))
+    {
+      /* Push for 16_bit.  */
+      int offset = 0;
+      if (CSKY_16_IS_PUSH_R15 (insn))
+ {
+  stacksize += 4;
+  register_offsets[15] = stacksize;
+  if (csky_debug)
+    print_savedreg_msg (15, register_offsets, false);
+  offset += 4;
+ }
+      if (CSKY_16_PUSH_LIST1 (insn))
+ {
+  int num = CSKY_16_PUSH_LIST1 (insn);
+  int tmp = 0;
+  stacksize += num * 4;
+  offset += num * 4;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: push regs_array: r4-r%d\n",
+  4 + num - 1);
+    }
+  for (rn = 4; rn <= 4 + num - 1; rn++)
+    {
+       register_offsets[rn] = stacksize - tmp;
+       if (csky_debug)
+ {
+   fprintf_unfiltered (gdb_stdlog,
+       "csky: r%d saved at 0x%x"
+       " (offset %d)\n", rn,
+       register_offsets[rn], offset);
+ }
+       tmp += 4;
+    }
+ }
+
+      framesize = stacksize;
+      if (csky_debug)
+ fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+      continue;
+    }
+  else if (CSKY_16_IS_LRW4 (insn) || CSKY_16_IS_MOVI4 (insn))
+    {
+      int adjust = 0;
+      int offset = 0;
+      unsigned int insn2;
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: looking at large frame\n");
+ }
+      if (CSKY_16_IS_LRW4 (insn))
+ {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int offset = ((insn & 0x300) >> 3) | (insn & 0x1f);
+  int literal_addr = (addr + ( offset << 2)) & 0xfffffffc;
+  adjust = read_memory_unsigned_integer (literal_addr, 4,
+ byte_order);
+ }
+      else
+ {
+  /* CSKY_16_IS_MOVI4 (insn).  */
+  adjust = (insn  & 0xff);
+ }
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: base stacksize=0x%x\n", adjust);
+ }
+
+      /* May have zero or more instructions which modify r4.  */
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: looking for r4 adjusters...\n");
+ }
+      offset = 2;
+      insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+      while (CSKY_IS_R4_ADJUSTER (insn2))
+ {
+  if (CSKY_32_IS_ADDI4 (insn2))
+    {
+      int imm = (insn2 & 0xfff) + 1;
+      adjust += imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: addi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_SUBI4 (insn2))
+    {
+      int imm = (insn2 & 0xfff) + 1;
+      adjust -= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: subi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_NOR4 (insn2))
+    {
+      adjust = ~adjust;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: nor r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_32_IS_ROTLI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      int temp = adjust >> (32 - imm);
+      adjust <<= imm;
+      adjust |= temp;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: rotli r4,r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_LISI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust <<= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: lsli r4,r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_BSETI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust |= (1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bseti r4,r4 %d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_BCLRI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust &= ~(1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bclri r4,r4 %d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_IXH4 (insn2))
+    {
+      adjust *= 3;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: ixh r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_32_IS_IXW4 (insn2))
+    {
+      adjust *= 5;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: ixw r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_16_IS_ADDI4 (insn2))
+    {
+      int imm = (insn2 & 0xff) + 1;
+      adjust += imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: addi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_SUBI4 (insn2))
+    {
+      int imm = (insn2 & 0xff) + 1;
+      adjust -= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: subi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_NOR4 (insn2))
+    {
+      adjust = ~adjust;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: nor r4,r4\n");
+ }
+    }
+  else if (CSKY_16_IS_BSETI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust |= (1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bseti r4, %d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_BCLRI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust &= ~(1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bclri r4, %d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_LSLI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust <<= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: lsli r4,r4, %d\n", imm);
+ }
+    }
+
+  offset += insn_len;
+  insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+ };
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog, "csky: "
+      "done looking for r4 adjusters\n");
+ }
+
+      /* If the next instruction adjusts the stack pointer, we keep
+ everything; if not, we scrap it and we've found the end
+ of the prologue.  */
+      if (CSKY_IS_SUBU4 (insn2))
+ {
+  addr += offset;
+  stacksize += adjust;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "csky: "
+  "found stack adjustment of 0x%x"
+  " bytes.\n", adjust);
+      fprintf_unfiltered (gdb_stdlog, "csky: "
+  "skipping to new address 0x%lx\n",
+  addr);
+      fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+    }
+  continue;
+ }
+
+      /* None of these instructions are prologue, so don't touch
+ anything.  */
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog, "csky: no subu sp,r4; "
+      "NOT altering stacksize.\n");
+ }
+      break;
+    }
+ }
+
+      /* This is not a prologue instruction, so stop here.  */
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog, "csky: insn is not a prologue"
+      " insn -- ending scan\n");
+ }
+      break;
+    }
+
+  if (this_cache)
+    {
+      CORE_ADDR unwound_fp;
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      this_cache->framesize = framesize;
+
+      if (is_fp_saved)
+ {
+  this_cache->framereg = CSKY_FP_REGNUM;
+  unwound_fp = get_frame_register_unsigned (this_frame,
+    this_cache->framereg);
+  this_cache->prev_sp = unwound_fp + adjust_fp;
+ }
+      else
+ {
+  this_cache->framereg = CSKY_SP_REGNUM;
+  unwound_fp = get_frame_register_unsigned (this_frame,
+    this_cache->framereg);
+  this_cache->prev_sp = unwound_fp + stacksize;
+ }
+
+      /* Note where saved registers are stored.  The offsets in
+ REGISTER_OFFSETS are computed relative to the top of the frame.  */
+      for (rn = 0; rn < CSKY_NUM_GREGS; rn++)
+ {
+  if (register_offsets[rn] >= 0)
+    {
+      this_cache->saved_regs[rn].addr
+ = this_cache->prev_sp - register_offsets[rn];
+      if (csky_debug)
+ {
+  CORE_ADDR rn_value = read_memory_unsigned_integer (
+    this_cache->saved_regs[rn].addr, 4, byte_order);
+  fprintf_unfiltered (gdb_stdlog, "Saved register %s "
+      "stored at 0x%08lx, value=0x%08lx\n",
+      csky_register_names[rn],
+      (unsigned long)
+ this_cache->saved_regs[rn].addr,
+      (unsigned long) rn_value);
+ }
+    }
+ }
+      if (lr_type == LR_TYPE_EPC)
+ {
+  /* rte || epc .  */
+  this_cache->saved_regs[CSKY_PC_REGNUM]
+    = this_cache->saved_regs[CSKY_EPC_REGNUM];
+ }
+      else if (lr_type == LR_TYPE_FPC)
+ {
+  /* rfi || fpc .  */
+  this_cache->saved_regs[CSKY_PC_REGNUM]
+    = this_cache->saved_regs[CSKY_FPC_REGNUM];
+ }
+      else
+ {
+  this_cache->saved_regs[CSKY_PC_REGNUM]
+    = this_cache->saved_regs[CSKY_LR_REGNUM];
+ }
+    }
+
+  return addr;
+}
+
+/* Detect whether PC is at a point where the stack frame has been
+   destroyed.  */
+
+static int
+csky_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  unsigned int insn;
+  CORE_ADDR addr;
+  CORE_ADDR func_start, func_end;
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  bool fp_saved = false;
+  int insn_len;
+  for (addr = func_start; addr < func_end; addr += insn_len)
+    {
+      /* Get next insn.  */
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+
+      if (insn_len == 2)
+ {
+  /* Is sp is saved to fp.  */
+  if (CSKY_16_IS_MOV_FP_SP (insn))
+    fp_saved = true;
+  /* If sp was saved to fp and now being restored from
+     fp then it indicates the start of epilog.  */
+  else if (fp_saved && CSKY_16_IS_MOV_SP_FP (insn))
+    return pc >= addr;
+ }
+    }
+  return 0;
+}
+
+/* Implement the skip_prologue gdbarch hook.  */
+
+static CORE_ADDR
+csky_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal;
+  LONGEST return_value;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  const int default_search_limit = 128;
+
+  /* See if we can find the end of the prologue using the symbol table.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    {
+      CORE_ADDR post_prologue_pc
+ = skip_prologue_using_sal (gdbarch, func_addr);
+
+      if (post_prologue_pc != 0)
+ return std::max (pc, post_prologue_pc);
+    }
+  else
+    func_end = pc + default_search_limit;
+
+  /* Find the end of prologue.  Default lr_type.  */
+  return csky_analyze_prologue (gdbarch, pc, func_end, func_end,
+ NULL, NULL, LR_TYPE_R15);
+}
+
+/* Implement the breakpoint_kind_from_pc gdbarch method.  */
+
+static int
+csky_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+  if (csky_pc_is_csky16 (gdbarch, *pcptr))
+    return CSKY_INSN_SIZE16;
+  else
+    return CSKY_INSN_SIZE32;
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method.  */
+
+static const gdb_byte *
+csky_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+  *size = kind;
+  if (kind == CSKY_INSN_SIZE16)
+    {
+      static gdb_byte csky_16_breakpoint[] = { 0, 0 };
+      return csky_16_breakpoint;
+    }
+  else
+    {
+      static gdb_byte csky_32_breakpoint[] = { 0, 0, 0, 0 };
+      return csky_32_breakpoint;
+    }
+}
+
+/* Implement the memory_insert_breakpoint gdbarch method.  */
+
+static int
+csky_memory_insert_breakpoint (struct gdbarch *gdbarch,
+       struct bp_target_info *bp_tgt)
+{
+  int val;
+  const unsigned char *bp;
+  gdb_byte bp_write_record1[] = { 0, 0, 0, 0 };
+  gdb_byte bp_write_record2[] = { 0, 0, 0, 0 };
+  gdb_byte bp_record[] = { 0, 0, 0, 0 };
+
+  /* Sanity-check bp_address.  */
+  if (bp_tgt->reqstd_address % 2)
+    warning (_("Invalid breakpoint address 0x%x is an odd number.\n"),
+     (unsigned int) bp_tgt->reqstd_address);
+  scoped_restore restore_memory
+    = make_scoped_restore_show_memory_breakpoints (1);
+
+  /* Determine appropriate breakpoint_kind for this address.  */
+  bp_tgt->kind = csky_breakpoint_kind_from_pc (gdbarch,
+       &bp_tgt->reqstd_address);
+
+  /* Save the memory contents.  */
+  bp_tgt->shadow_len = bp_tgt->kind;
+
+  /* Fill bp_tgt->placed_address.  */
+  bp_tgt->placed_address = bp_tgt->reqstd_address;
+
+  if (bp_tgt->kind == CSKY_INSN_SIZE16)
+    {
+      if ((bp_tgt->reqstd_address % 4) == 0)
+ {
+  /* Read two bytes.  */
+  val = target_read_memory (bp_tgt->reqstd_address,
+    bp_tgt->shadow_contents, 2);
+  if (val)
+    return val;
+
+  /* Read two bytes.  */
+  val = target_read_memory (bp_tgt->reqstd_address + 2,
+    bp_record, 2);
+  if (val)
+    return val;
+
+  /* Write the breakpoint.  */
+  bp_write_record1[2] = bp_record[0];
+  bp_write_record1[3] = bp_record[1];
+  bp = bp_write_record1;
+  val = target_write_raw_memory (bp_tgt->reqstd_address, bp,
+ CSKY_WR_BKPT_MODE);
+ }
+      else
+ {
+  val = target_read_memory (bp_tgt->reqstd_address,
+    bp_tgt->shadow_contents, 2);
+  if (val)
+    return val;
+
+  val = target_read_memory (bp_tgt->reqstd_address - 2,
+    bp_record, 2);
+  if (val)
+    return val;
+
+  /* Write the breakpoint.  */
+  bp_write_record1[0] = bp_record[0];
+  bp_write_record1[1] = bp_record[1];
+  bp = bp_write_record1;
+  val = target_write_raw_memory (bp_tgt->reqstd_address - 2,
+ bp, CSKY_WR_BKPT_MODE);
+ }
+    }
+  else
+    {
+      if (bp_tgt->placed_address % 4 == 0)
+ {
+  val = target_read_memory (bp_tgt->reqstd_address,
+    bp_tgt->shadow_contents,
+    CSKY_WR_BKPT_MODE);
+  if (val)
+    return val;
+
+  /* Write the breakpoint.  */
+  bp = bp_write_record1;
+  val = target_write_raw_memory (bp_tgt->reqstd_address,
+ bp, CSKY_WR_BKPT_MODE);
+ }
+      else
+ {
+  val = target_read_memory (bp_tgt->reqstd_address,
+    bp_tgt->shadow_contents,
+    CSKY_WR_BKPT_MODE);
+  if (val)
+    return val;
+
+  val = target_read_memory (bp_tgt->reqstd_address - 2,
+    bp_record, 2);
+  if (val)
+    return val;
+
+  val = target_read_memory (bp_tgt->reqstd_address + 4,
+    bp_record + 2, 2);
+  if (val)
+    return val;
+
+  bp_write_record1[0] = bp_record[0];
+  bp_write_record1[1] = bp_record[1];
+  bp_write_record2[2] = bp_record[2];
+  bp_write_record2[3] = bp_record[3];
+
+  /* Write the breakpoint.  */
+  bp = bp_write_record1;
+  val = target_write_raw_memory (bp_tgt->reqstd_address - 2, bp,
+ CSKY_WR_BKPT_MODE);
+  if (val)
+    return val;
+
+  /* Write the breakpoint.  */
+  bp = bp_write_record2;
+  val = target_write_raw_memory (bp_tgt->reqstd_address + 2, bp,
+ CSKY_WR_BKPT_MODE);
+ }
+    }
+  return val;
+}
+
+/* Restore the breakpoint shadow_contents to the target.  */
+
+static int
+csky_memory_remove_breakpoint (struct gdbarch *gdbarch,
+       struct bp_target_info *bp_tgt)
+{
+  int val;
+  gdb_byte bp_record[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+  /* Different for shadow_len 2 or 4.  */
+  if (bp_tgt->shadow_len == 2)
+    {
+      /* Do word-sized writes on word-aligned boundaries and read
+ padding bytes as necessary.  */
+      if (bp_tgt->reqstd_address % 4 == 0)
+ {
+  val = target_read_memory (bp_tgt->reqstd_address + 2,
+    bp_record + 2, 2);
+  if (val)
+    return val;
+  bp_record[0] = bp_tgt->shadow_contents[0];
+  bp_record[1] = bp_tgt->shadow_contents[1];
+  return target_write_raw_memory (bp_tgt->reqstd_address,
+  bp_record, CSKY_WR_BKPT_MODE);
+ }
+      else
+ {
+  val = target_read_memory (bp_tgt->reqstd_address - 2,
+    bp_record, 2);
+  if (val)
+    return val;
+  bp_record[2] = bp_tgt->shadow_contents[0];
+  bp_record[3] = bp_tgt->shadow_contents[1];
+  return target_write_raw_memory (bp_tgt->reqstd_address - 2,
+  bp_record, CSKY_WR_BKPT_MODE);
+ }
+    }
+  else
+    {
+      /* Do word-sized writes on word-aligned boundaries and read
+ padding bytes as necessary.  */
+      if (bp_tgt->placed_address % 4 == 0)
+ {
+  return target_write_raw_memory (bp_tgt->reqstd_address,
+  bp_tgt->shadow_contents,
+  CSKY_WR_BKPT_MODE);
+ }
+      else
+ {
+  val = target_read_memory (bp_tgt->reqstd_address - 2,
+    bp_record, 2);
+  if (val)
+    return val;
+  val = target_read_memory (bp_tgt->reqstd_address + 4,
+    bp_record+6, 2);
+  if (val)
+    return val;
+
+  bp_record[2] = bp_tgt->shadow_contents[0];
+  bp_record[3] = bp_tgt->shadow_contents[1];
+  bp_record[4] = bp_tgt->shadow_contents[2];
+  bp_record[5] = bp_tgt->shadow_contents[3];
+
+  return target_write_raw_memory (bp_tgt->reqstd_address - 2,
+  bp_record,
+  CSKY_WR_BKPT_MODE * 2);
+ }
+    }
+}
+
+/* Determine link register type.  */
+
+static lr_type_t
+csky_analyze_lr_type (struct gdbarch *gdbarch,
+      CORE_ADDR start_pc, CORE_ADDR end_pc)
+{
+  CORE_ADDR addr;
+  unsigned int insn, rn, insn_len;
+  insn_len = 2;
+
+  for (addr = start_pc; addr < end_pc; addr += insn_len)
+    {
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+      if (insn_len == 4)
+ {
+  if (CSKY_32_IS_MFCR_EPSR (insn) || CSKY_32_IS_MFCR_EPC (insn)
+      || CSKY_32_IS_RTE (insn))
+    return LR_TYPE_EPC;
+ }
+      else if (CSKY_32_IS_MFCR_FPSR (insn) || CSKY_32_IS_MFCR_FPC (insn)
+       || CSKY_32_IS_RFI (insn))
+ return LR_TYPE_FPC;
+      else if (CSKY_32_IS_JMP (insn) || CSKY_32_IS_BR (insn)
+       || CSKY_32_IS_JMPIX (insn) || CSKY_32_IS_JMPI (insn))
+ return LR_TYPE_R15;
+      else
+ {
+  /* 16 bit instruction.  */
+  if (CSKY_16_IS_JMP (insn) || CSKY_16_IS_BR (insn)
+      || CSKY_16_IS_JMPIX (insn))
+    return LR_TYPE_R15;
+ }
+    }
+    return LR_TYPE_R15;
+}
+
+/* Heuristic unwinder.  */
+
+static struct csky_unwind_cache *
+csky_frame_unwind_cache (struct frame_info *this_frame)
+{
+  CORE_ADDR prologue_start, prologue_end, func_end, prev_pc, block_addr;
+  struct csky_unwind_cache *cache;
+  const struct block *bl;
+  unsigned long func_size = 0;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  unsigned int sp_regnum = CSKY_SP_REGNUM;
+
+  /* Default lr type is r15.  */
+  lr_type_t lr_type = LR_TYPE_R15;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct csky_unwind_cache);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  /* Assume there is no frame until proven otherwise.  */
+  cache->framereg = sp_regnum;
+
+  cache->framesize = 0;
+
+  prev_pc = get_frame_pc (this_frame);
+  block_addr = get_frame_address_in_block (this_frame);
+  if (find_pc_partial_function (block_addr, NULL, &prologue_start,
+ &func_end) == 0)
+    /* We couldn't find a function containing block_addr, so bail out
+       and hope for the best.  */
+    return cache;
+
+  /* Get the (function) symbol matching prologue_start.  */
+  bl = block_for_pc (prologue_start);
+  if (bl != NULL)
+    func_size = bl->endaddr - bl->startaddr;
+  else
+    {
+      struct bound_minimal_symbol msymbol
+ = lookup_minimal_symbol_by_pc (prologue_start);
+      if (msymbol.minsym != NULL)
+ func_size = MSYMBOL_SIZE (msymbol.minsym);
+    }
+
+  /* If FUNC_SIZE is 0 we may have a special-case use of lr
+     e.g. exception or interrupt.  */
+  if (func_size == 0)
+    lr_type = csky_analyze_lr_type (gdbarch, prologue_start, func_end);
+
+  prologue_end = std::min (func_end, prev_pc);
+
+  /* Analyze the function prologue.  */
+  csky_analyze_prologue (gdbarch, prologue_start, prologue_end,
+    func_end, this_frame, cache, lr_type);
+
+  /* gdbarch_sp_regnum contains the value and not the address.  */
+  trad_frame_set_value (cache->saved_regs, sp_regnum, cache->prev_sp);
+  return cache;
+}
+
+/* Implement the unwind_pc gdbarch method.  */
+
+static CORE_ADDR
+csky_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, CSKY_PC_REGNUM);
+}
+
+/* Implement the this_id function for the normal unwinder.  */
+
+static void
+csky_frame_this_id (struct frame_info *this_frame,
+    void **this_prologue_cache, struct frame_id *this_id)
+{
+  struct csky_unwind_cache *cache;
+  struct frame_id id;
+
+  if (*this_prologue_cache == NULL)
+    *this_prologue_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_prologue_cache;
+
+  /* This marks the outermost frame.  */
+  if (cache->prev_sp == 0)
+    return;
+
+  id = frame_id_build (cache->prev_sp, get_frame_func (this_frame));
+  *this_id = id;
+}
+
+/* Implement the prev_register function for the normal unwinder.  */
+
+static struct value *
+csky_frame_prev_register (struct frame_info *this_frame,
+  void **this_prologue_cache, int regnum)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_prologue_cache == NULL)
+    *this_prologue_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_prologue_cache;
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+       regnum);
+}
+
+/* Data structures for the normal prologue-analysis-based
+   unwinder.  */
+
+static const struct frame_unwind csky_unwind_cache = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  csky_frame_this_id,
+  csky_frame_prev_register,
+  NULL,
+  default_frame_sniffer,
+  NULL,
+  NULL
+};
+
+
+
+static int
+csky_stub_unwind_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+  CORE_ADDR addr_in_block;
+
+  addr_in_block = get_frame_address_in_block (this_frame);
+
+  if (find_pc_partial_function (addr_in_block, NULL, NULL, NULL) == 0
+      || in_plt_section (addr_in_block))
+    return 1;
+
+  return 0;
+}
+
+static struct csky_unwind_cache *
+csky_make_stub_cache (struct frame_info *this_frame)
+{
+  struct csky_unwind_cache *cache;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct csky_unwind_cache);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  cache->prev_sp = get_frame_register_unsigned (this_frame,
CSKY_SP_REGNUM);
+
+  return cache;
+}
+
+static void
+csky_stub_this_id (struct frame_info *this_frame,
+  void **this_cache,
+  struct frame_id *this_id)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_make_stub_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  /* Our frame ID for a stub frame is the current SP and LR.  */
+  *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
+}
+
+static struct value *
+csky_stub_prev_register (struct frame_info *this_frame,
+    void **this_cache,
+    int prev_regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_make_stub_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  /* If we are asked to unwind the PC, then return the LR.  */
+  if (prev_regnum == CSKY_PC_REGNUM)
+    {
+      CORE_ADDR lr;
+
+      lr = frame_unwind_register_unsigned (this_frame, CSKY_LR_REGNUM);
+      return frame_unwind_got_constant (this_frame, prev_regnum, lr);
+    }
+
+  if (prev_regnum == CSKY_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, prev_regnum,
cache->prev_sp);
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+       prev_regnum);
+}
+
+struct frame_unwind csky_stub_unwind = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  csky_stub_this_id,
+  csky_stub_prev_register,
+  NULL,
+  csky_stub_unwind_sniffer
+};
+
+/* Implement the this_base, this_locals, and this_args hooks
+   for the normal unwinder.  */
+
+static CORE_ADDR
+csky_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  return cache->prev_sp - cache->framesize;
+}
+
+static const struct frame_base csky_frame_base = {
+  &csky_unwind_cache,
+  csky_frame_base_address,
+  csky_frame_base_address,
+  csky_frame_base_address
+};
+
+/* Implement the dummy_id gdbarch method.  The frame ID's base
+   needs to match the TOS value saved by save_dummy_frame_tos,
+   and the PC should match the dummy frame's breakpoint.  */
+
+static struct frame_id
+csky_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  unsigned int sp_regnum = CSKY_SP_REGNUM;
+
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, sp_regnum);
+  return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+/* Initialize register access method.  */
+
+static void
+csky_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+    struct dwarf2_frame_state_reg *reg,
+    struct frame_info *this_frame)
+{
+  if (regnum == gdbarch_pc_regnum (gdbarch))
+    reg->how = DWARF2_FRAME_REG_RA;
+  else if (regnum == gdbarch_sp_regnum (gdbarch))
+    reg->how = DWARF2_FRAME_REG_CFA;
+}
+
+/* Create csky register groups.  */
+
+static void
+csky_init_reggroup ()
+{
+  cr_reggroup = reggroup_new ("cr", USER_REGGROUP);
+  fr_reggroup = reggroup_new ("fr", USER_REGGROUP);
+  vr_reggroup = reggroup_new ("vr", USER_REGGROUP);
+  mmu_reggroup = reggroup_new ("mmu", USER_REGGROUP);
+  prof_reggroup = reggroup_new ("profiling", USER_REGGROUP);
+}
+
+/* Add register groups into reggroup list.  */
+
+static void
+csky_add_reggroups (struct gdbarch *gdbarch)
+{
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, cr_reggroup);
+  reggroup_add (gdbarch, fr_reggroup);
+  reggroup_add (gdbarch, vr_reggroup);
+  reggroup_add (gdbarch, mmu_reggroup);
+  reggroup_add (gdbarch, prof_reggroup);
+}
+
+/* Return the groups that a CSKY register can be categorised into.  */
+
+static int
+csky_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+  struct reggroup *reggroup)
+{
+  int raw_p;
+
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
+    return 0;
+
+  if (reggroup == all_reggroup)
+    return 1;
+
+  raw_p = regnum < gdbarch_num_regs (gdbarch);
+  if (reggroup == save_reggroup || reggroup == restore_reggroup)
+    return raw_p;
+
+  if (((regnum >= CSKY_R0_REGNUM) && (regnum <= CSKY_R0_REGNUM + 31))
+      && (reggroup == general_reggroup))
+    return 1;
+
+  if (((regnum == CSKY_PC_REGNUM)
+       || ((regnum >= CSKY_CR0_REGNUM)
+   && (regnum <= CSKY_CR0_REGNUM + 30)))
+      && (reggroup == cr_reggroup))
+    return 2;
+
+  if ((((regnum >= CSKY_VR0_REGNUM) && (regnum <= CSKY_VR0_REGNUM + 15))
+       || ((regnum >= CSKY_VCR0_REGNUM)
+   && (regnum <= CSKY_VCR0_REGNUM + 2)))
+      && (reggroup == vr_reggroup))
+    return 3;
+
+  if (((regnum >= CSKY_MMU_REGNUM) && (regnum <= CSKY_MMU_REGNUM + 8))
+      && (reggroup == mmu_reggroup))
+    return 4;
+
+  if (((regnum >= CSKY_PROFCR_REGNUM)
+       && (regnum <= CSKY_PROFCR_REGNUM + 48))
+      && (reggroup == prof_reggroup))
+    return 5;
+
+  if ((((regnum >= CSKY_FR0_REGNUM) && (regnum <= CSKY_FR0_REGNUM + 15))
+       || ((regnum >= CSKY_VCR0_REGNUM) && (regnum <= CSKY_VCR0_REGNUM
+ 2)))
+      && (reggroup == fr_reggroup))
+    return 6;
+
+  return 0;
+}
+
+/* Implement the dwarf2_reg_to_regnum gdbarch method.  */
+
+static int
+csky_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int dw_reg)
+{
+  if (dw_reg < 0 || dw_reg >= CSKY_NUM_REGS)
+    return -1;
+  return dw_reg;
+}
+
+/* Override interface for command: info register.  */
+
+static void
+csky_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
+   struct frame_info *frame, int regnum, int all)
+{
+  /* Call default print_registers_info function.  */
+  default_print_registers_info (gdbarch, file, frame, regnum, all);
+
+  /* For command: info register.  */
+  if (regnum == -1 && all == 0)
+    {
+      default_print_registers_info (gdbarch, file, frame,
+    CSKY_PC_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+    CSKY_EPC_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+    CSKY_CR0_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+    CSKY_EPSR_REGNUM, 0);
+    }
+  return;
+}
+
+/* Initialize the current architecture based on INFO.  If possible,
+   re-use an architecture from ARCHES, which is a list of
+   architectures already created during this debugging session.
+
+   Called at program startup, when reading a core file, and when
+   reading a binary file.  */
+
+static struct gdbarch *
+csky_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+
+  /* Find a candidate among the list of pre-declared architectures.  */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return arches->gdbarch;
+
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = XCNEW (struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* Target data types.  */
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_addr_bit (gdbarch, 32);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+
+  /* Information about the target architecture.  */
+  set_gdbarch_return_value (gdbarch, csky_return_value);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch,
csky_breakpoint_kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch,
csky_sw_breakpoint_from_kind);
+
+  /* Register architecture.  */
+  set_gdbarch_num_regs (gdbarch, CSKY_NUM_REGS);
+  set_gdbarch_pc_regnum (gdbarch, CSKY_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CSKY_SP_REGNUM);
+  set_gdbarch_register_name (gdbarch, csky_register_name);
+  set_gdbarch_register_type (gdbarch, csky_register_type);
+  set_gdbarch_read_pc (gdbarch, csky_read_pc);
+  set_gdbarch_write_pc (gdbarch, csky_write_pc);
+  set_gdbarch_print_registers_info (gdbarch, csky_print_registers_info);
+  csky_add_reggroups (gdbarch);
+  set_gdbarch_register_reggroup_p (gdbarch, csky_register_reggroup_p);
+  set_gdbarch_stab_reg_to_regnum (gdbarch, csky_dwarf_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, csky_dwarf_reg_to_regnum);
+  dwarf2_frame_set_init_reg (gdbarch, csky_dwarf2_frame_init_reg);
+
+  /* Functions to analyze frames.  */
+  frame_base_set_default (gdbarch, &csky_frame_base);
+  set_gdbarch_skip_prologue (gdbarch, csky_skip_prologue);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_frame_align (gdbarch, csky_frame_align);
+  set_gdbarch_stack_frame_destroyed_p (gdbarch,
csky_stack_frame_destroyed_p);
+
+  /* Functions to access frame data.  */
+  set_gdbarch_unwind_pc (gdbarch, csky_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, csky_unwind_sp);
+
+  /* Functions handling dummy frames.  */
+  set_gdbarch_push_dummy_call (gdbarch, csky_push_dummy_call);
+  set_gdbarch_dummy_id (gdbarch, csky_dummy_id);
+
+  /* Frame unwinders.  Use DWARF debug info if available,
+     otherwise use our own unwinder.  */
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &csky_stub_unwind);
+  frame_unwind_append_unwinder (gdbarch, &csky_unwind_cache);
+
+  /* Breakpoints.  */
+  set_gdbarch_memory_insert_breakpoint (gdbarch,
+ csky_memory_insert_breakpoint);
+  set_gdbarch_memory_remove_breakpoint (gdbarch,
+ csky_memory_remove_breakpoint);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Support simple overlay manager.  */
+  set_gdbarch_overlay_update (gdbarch, simple_overlay_update);
+  set_gdbarch_char_signed (gdbarch, 0);
+  return gdbarch;
+}
+
+void
+_initialize_csky_tdep (void)
+{
+
+  register_gdbarch_init (bfd_arch_csky, csky_gdbarch_init);
+
+  csky_init_reggroup ();
+
+  /* Allow debugging this file's internals.  */
+  add_setshow_boolean_cmd ("csky", class_maintenance, &csky_debug,
+   _("Set C-Sky debugging."),
+   _("Show C-Sky debugging."),
+   _("When on, C-Sky specific debugging is enabled."),
+   NULL,
+   NULL,
+   &setdebuglist, &showdebuglist);
+}
diff --git a/gdb/csky-tdep.h b/gdb/csky-tdep.h
new file mode 100644
index 0000000000..49c29a9e1c
--- /dev/null
+++ b/gdb/csky-tdep.h
@@ -0,0 +1,355 @@
+/* Target-dependent code for the CSKY architecture, for GDB.
+
+   Copyright (C) 2010-2018 Free Software Foundation, 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/>.  */
+
+#ifndef CSKY_TDEP_H
+#define CSKY_TDEP_H
+
+/* How to interpret the contents of the link register.  */
+enum lr_type_t
+{
+  LR_TYPE_R15,
+  LR_TYPE_EPC,
+  LR_TYPE_FPC
+};
+
+/* Target-dependent structure in gdbarch.  */
+struct gdbarch_tdep
+{
+  /* This is Unused.  */
+};
+
+/* Instruction sizes.  */
+enum csky_insn_size_t
+{
+  CSKY_INSN_SIZE16 = 2,
+  CSKY_INSN_SIZE32 = 4
+};
+
+/* CSKY register numbers.  */
+enum csky_regnum
+{
+  CSKY_R0_REGNUM = 0, /* General registers.  */
+  CSKY_R15_REGNUM = 15,
+  CSKY_PC_REGNUM = 72,
+  CSKY_HI_REGNUM = 20,
+  CSKY_LO_REGNUM = 21,
+  CSKY_CR0_REGNUM = 89,
+  CSKY_VBR_REGNUM = CSKY_CR0_REGNUM + 1,
+  CSKY_EPSR_REGNUM = CSKY_CR0_REGNUM + 2,
+  CSKY_FPSR_REGNUM = CSKY_CR0_REGNUM + 3,
+  CSKY_EPC_REGNUM = CSKY_CR0_REGNUM + 4,
+  CSKY_FPC_REGNUM = CSKY_CR0_REGNUM + 5,
+
+  /* Float register 0.  */
+  CSKY_FR0_REGNUM = 40,
+  CSKY_VCR0_REGNUM = 121,
+  CSKY_MMU_REGNUM = 128,
+  CSKY_PROFCR_REGNUM = 140,
+  CSKY_PROFGR_REGNUM = 144,
+  CSKY_FP_REGNUM = 8,
+
+  /* Vector register 0.  */
+  CSKY_VR0_REGNUM = 56,
+
+  /* m32r calling convention.  */
+  CSKY_SP_REGNUM = CSKY_R0_REGNUM + 14,
+  CSKY_RET_REGNUM = CSKY_R0_REGNUM,
+
+  /* Argument registers.  */
+  CSKY_ABI_A0_REGNUM = 0,
+  CSKY_ABI_LAST_ARG_REGNUM = 3,
+
+  /* Link register, r15.  */
+  CSKY_LR_REGNUM = CSKY_R15_REGNUM,
+
+  /* Processor status register, cr0.  */
+  CSKY_PSR_REGNUM = CSKY_CR0_REGNUM,
+
+  CSKY_MAX_REGISTER_SIZE = 16,
+  CSKY_MAX_REGS = 253
+};
+
+/* ICE registers.  */
+#define CSKY_CRBANK_NUM_REGS 32
+
+/* Number of processor registers w/o ICE registers.  */
+#define CSKY_NUM_REGS (CSKY_MAX_REGS - CSKY_CRBANK_NUM_REGS)
+
+/* size.  */
+#define CSKY_16_ST_SIZE(insn) (1 << ((insn & 0x1800) >> 11))
+/* rx.  */
+#define CSKY_16_ST_ADDR_REGNUM(insn) ((insn & 0x700) >> 8)
+/* disp.  */
+#define CSKY_16_ST_OFFSET(insn) ((insn & 0x1f) << ((insn & 0x1800) >> 11))
+/* ry.  */
+#define CSKY_16_ST_VAL_REGNUM(insn) ((insn & 0xe0) >> 5)
+
+/* st16.w rz, (sp, disp).  */
+#define CSKY_16_IS_STWx0(insn) ((insn & 0xf800) == 0xb800)
+#define CSKY_16_STWx0_VAL_REGNUM(insn) CSKY_16_ST_ADDR_REGNUM (insn)
+
+/* disp.  */
+#define CSKY_16_STWx0_OFFSET(insn) \
+  ((((insn & 0x700) >> 3) + (insn & 0x1f)) << 2)
+
+/* Check ld16 but not ld16 sp.  */
+#define CSKY_16_IS_LD(insn) \
+  (((insn & 0xe000) == 0x8000) && (insn & 0x1800) != 0x1800)
+/* size.  */
+#define CSKY_16_LD_SIZE(insn) CSKY_16_ST_SIZE (insn)
+/* rx.  */
+#define CSKY_16_LD_ADDR_REGNUM(insn) CSKY_16_ST_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_16_LD_OFFSET(insn) CSKY_16_ST_OFFSET (insn)
+
+/* ld16.w rz,(sp,disp).  */
+#define CSKY_16_IS_LDWx0(insn) ((insn & 0xf800) == 0x9800)
+/*disp.  */
+#define CSKY_16_LDWx0_OFFSET(insn) CSKY_16_STWx0_OFFSET (insn)
+
+/* st32.b/h/w/d.  */
+#define CSKY_32_IS_ST(insn) ((insn & 0xfc00c000) == 0xdc000000)
+
+/* size: b/h/w/d.  */
+#define CSKY_32_ST_SIZE(insn) (1 << ((insn & 0x3000) >> 12))
+/* rx.  */
+#define CSKY_32_ST_ADDR_REGNUM(insn) ((insn & 0x001f0000) >> 16)
+/* disp.  */
+#define CSKY_32_ST_OFFSET(insn) ((insn & 0xfff) << ((insn & 0x3000) >> 12))
+/* ry.  */
+#define CSKY_32_ST_VAL_REGNUM(insn) ((insn & 0x03e00000) >> 21)
+
+/* stw ry, (sp, disp).  */
+#define CSKY_32_IS_STWx0(insn) ((insn & 0xfc1ff000) == 0xdc0e2000)
+
+/* stm32 ry-rz, (rx).  */
+#define CSKY_32_IS_STM(insn) ((insn & 0xfc00ffe0) == 0xd4001c20)
+/* rx.  */
+#define CSKY_32_STM_ADDR_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* Count of registers.  */
+#define CSKY_32_STM_SIZE(insn) (insn & 0x1f)
+/* ry.  */
+#define CSKY_32_STM_VAL_REGNUM(insn) ((insn & 0x03e00000) >> 21)
+/* stm32 ry-rz, (sp).  */
+#define CSKY_32_IS_STMx0(insn) ((insn & 0xfc1fffe0) == 0xd40e1c20)
+
+/* str32.b/h/w rz, (rx, ry << offset).  */
+#define CSKY_32_IS_STR(insn) \
+  (((insn & 0xfc000000) == 0xd4000000) && !(CSKY_32_IS_STM (insn)))
+/* rx.  */
+#define CSKY_32_STR_X_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* ry.  */
+#define CSKY_32_STR_Y_REGNUM(insn) ((insn >> 21) & 0x1f)
+/* size: b/h/w.  */
+#define CSKY_32_STR_SIZE(insn) (1 << ((insn & 0x0c00) >> 10))
+/* imm (for rx + ry * imm).  */
+#define CSKY_32_STR_OFFSET(insn) ((insn & 0x000003e0) >> 5)
+
+/* stex32.w rz, (rx, disp).  */
+#define CSKY_32_IS_STEX(insn) ((insn & 0xfc00f000) == 0xdc007000)
+/* rx.  */
+#define CSKY_32_STEX_ADDR_REGNUM(insn) ((insn & 0x1f0000) >> 16)
+/* disp.  */
+#define CSKY_32_STEX_OFFSET(insn) ((insn & 0x0fff) << 2)
+
+/* ld.b/h/w.  */
+#define CSKY_32_IS_LD(insn) ((insn & 0xfc00c000) == 0xd8000000)
+/* size.  */
+#define CSKY_32_LD_SIZE(insn) CSKY_32_ST_SIZE (insn)
+/* rx.  */
+#define CSKY_32_LD_ADDR_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_32_LD_OFFSET(insn) CSKY_32_ST_OFFSET (insn)
+#define CSKY_32_IS_LDM(insn) ((insn & 0xfc00ffe0) == 0xd0001c20)
+/* rx.  */
+#define CSKY_32_LDM_ADDR_REGNUM(insn) CSKY_32_STM_ADDR_REGNUM (insn)
+/* Count of registers.  */
+#define CSKY_32_LDM_SIZE(insn) CSKY_32_STM_SIZE (insn)
+
+/* ldr32.b/h/w rz, (rx, ry << offset).  */
+#define CSKY_32_IS_LDR(insn) \
+  (((insn & 0xfc00fe00) == 0xd0000000) && !(CSKY_32_IS_LDM (insn)))
+/* rx.  */
+#define CSKY_32_LDR_X_REGNUM(insn) CSKY_32_STR_X_REGNUM (insn)
+/* ry.  */
+#define CSKY_32_LDR_Y_REGNUM(insn) CSKY_32_STR_Y_REGNUM (insn)
+/* size: b/h/w.  */
+#define CSKY_32_LDR_SIZE(insn) CSKY_32_STR_SIZE (insn)
+/* imm (for rx + ry*imm).  */
+#define CSKY_32_LDR_OFFSET(insn) CSKY_32_STR_OFFSET (insn)
+
+#define CSKY_32_IS_LDEX(insn) ((insn & 0xfc00f000) == 0xd8007000)
+/* rx.  */
+#define CSKY_32_LDEX_ADDR_REGNUM(insn) CSKY_32_STEX_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_32_LDEX_OFFSET(insn) CSKY_32_STEX_OFFSET (insn)
+
+/* subi.sp sp, disp.  */
+#define CSKY_16_IS_SUBI0(insn) ((insn & 0xfce0) == 0x1420)
+/* disp.  */
+#define CSKY_16_SUBI_IMM(insn) ((((insn & 0x300) >> 3) + (insn & 0x1f))
<< 2)
+
+/* subi32 sp,sp,oimm12.  */
+#define CSKY_32_IS_SUBI0(insn) ((insn & 0xfffff000) == 0xe5ce1000)
+/* oimm12.  */
+#define CSKY_32_SUBI_IMM(insn) ((insn & 0xfff) + 1)
+
+/* push16.  */
+#define CSKY_16_IS_PUSH(insn) ((insn & 0xffe0) == 0x14c0)
+#define CSKY_16_IS_PUSH_R15(insn) ((insn & 0x10) == 0x10)
+#define CSKY_16_PUSH_LIST1(insn) (insn & 0xf) /* r4 - r11.  */
+
+/* pop16.  */
+#define CSKY_16_IS_POP(insn) ((insn & 0xffe0) == 0x1480)
+#define CSKY_16_IS_POP_R15(insn) CSKY_16_IS_PUSH_R15 (insn)
+#define CSKY_16_POP_LIST1(insn) CSKY_16_PUSH_LIST1 (insn) /* r4 - r11.  */
+
+/* push32.  */
+#define CSKY_32_IS_PUSH(insn) ((insn & 0xfffffe00) == 0xebe00000)
+#define CSKY_32_IS_PUSH_R29(insn) ((insn & 0x100) == 0x100)
+#define CSKY_32_IS_PUSH_R15(insn) ((insn & 0x10) == 0x10)
+#define CSKY_32_PUSH_LIST1(insn) (insn & 0xf) /* r4 - r11.  */
+#define CSKY_32_PUSH_LIST2(insn) ((insn & 0xe0) >> 5) /* r16 - r17.  */
+
+/* pop32.  */
+#define CSKY_32_IS_POP(insn) ((insn & 0xfffffe00) == 0xebc00000)
+#define CSKY_32_IS_POP_R29(insn) CSKY_32_IS_PUSH_R29 (insn)
+#define CSKY_32_IS_POP_R15(insn) CSKY_32_IS_PUSH_R15 (insn)
+#define CSKY_32_POP_LIST1(insn) CSKY_32_PUSH_LIST1 (insn) /* r4 - r11.  */
+#define CSKY_32_POP_LIST2(insn) CSKY_32_PUSH_LIST2 (insn) /* r16 - r17.  */
+
+/* Adjust sp by r4(l0).  */
+/* lrw r4, literal.  */
+#define CSKY_16_IS_LRW4(x) (((x) &0xfce0) == 0x1080)
+/* movi r4, imm8.  */
+#define CSKY_16_IS_MOVI4(x) (((x) &0xff00) == 0x3400)
+
+/* addi r4, oimm8.  */
+#define CSKY_16_IS_ADDI4(x) (((x) &0xff00) == 0x2400)
+/* subi r4, oimm8.  */
+#define CSKY_16_IS_SUBI4(x) (((x) &0xff00) == 0x2c00)
+
+/* nor16 r4, r4.  */
+#define CSKY_16_IS_NOR4(x) ((x) == 0x6d12)
+
+/* lsli r4, r4, imm5.  */
+#define CSKY_16_IS_LSLI4(x) (((x) &0xffe0) == 0x4480)
+/* bseti r4, imm5.  */
+#define CSKY_16_IS_BSETI4(x) (((x) &0xffe0) == 0x3ca0)
+/* bclri r4, imm5.  */
+#define CSKY_16_IS_BCLRI4(x) (((x) &0xffe0) == 0x3c80)
+
+/* subu sp, r4.  */
+#define CSKY_16_IS_SUBU4(x) ((x) == 0x6392)
+
+#define CSKY_16_IS_R4_ADJUSTER(x) \
+  (CSKY_16_IS_ADDI4 (x) || CSKY_16_IS_SUBI4 (x) || CSKY_16_IS_BSETI4 (x) \
+   || CSKY_16_IS_BCLRI4 (x) || CSKY_16_IS_NOR4 (x) || CSKY_16_IS_LSLI4 (x))
+
+/* lrw r4, literal.  */
+#define CSKY_32_IS_LRW4(x) (((x) &0xffff0000) == 0xea840000)
+/* movi r4, imm16.  */
+#define CSKY_32_IS_MOVI4(x) (((x) &0xffff0000) == 0xea040000)
+/* movih r4, imm16.  */
+#define CSKY_32_IS_MOVIH4(x) (((x) &0xffff0000) == 0xea240000)
+/* bmaski r4, oimm5.  */
+#define CSKY_32_IS_BMASKI4(x) (((x) &0xfc1fffff) == 0xc4005024)
+/* addi r4, r4, oimm12.  */
+#define CSKY_32_IS_ADDI4(x) (((x) &0xfffff000) == 0xe4840000)
+/* subi r4, r4, oimm12.  */
+#define CSKY_32_IS_SUBI4(x) (((x) &0xfffff000) == 0xe4810000)
+
+/* nor32 r4, r4, r4.  */
+#define CSKY_32_IS_NOR4(x) ((x) == 0xc4842484)
+/* rotli r4, r4, imm5.  */
+#define CSKY_32_IS_ROTLI4(x) (((x) &0xfc1fffff) == 0xc4044904)
+/* lsli r4, r4, imm5.  */
+#define CSKY_32_IS_LISI4(x) (((x) &0xfc1fffff) == 0xc4044824)
+/* bseti32 r4, r4, imm5.  */
+#define CSKY_32_IS_BSETI4(x) (((x) &0xfc1fffff) == 0xc4042844)
+/* bclri32 r4, r4, imm5.  */
+#define CSKY_32_IS_BCLRI4(x) (((x) &0xfc1fffff) == 0xc4042824)
+/* ixh r4, r4, r4.  */
+#define CSKY_32_IS_IXH4(x) ((x) == 0xc4840824)
+/* ixw r4, r4, r4.  */
+#define CSKY_32_IS_IXW4(x) ((x) == 0xc4840844)
+/* subu32 sp, sp, r4.  */
+#define CSKY_32_IS_SUBU4(x) ((x) == 0xc48e008e)
+
+#define CSKY_32_IS_R4_ADJUSTER(x) \
+  (CSKY_32_IS_ADDI4 (x) || CSKY_32_IS_SUBI4 (x) || CSKY_32_IS_ROTLI4 (x) \
+   || CSKY_32_IS_IXH4 (x) || CSKY_32_IS_IXW4 (x) || CSKY_32_IS_NOR4 (x) \
+   || CSKY_32_IS_BSETI4 (x) || CSKY_32_IS_BCLRI4 (x) ||
CSKY_32_IS_LISI4 (x))
+
+#define CSKY_IS_R4_ADJUSTER(x) \
+  (CSKY_32_IS_R4_ADJUSTER (x) || CSKY_16_IS_R4_ADJUSTER (x))
+#define CSKY_IS_SUBU4(x) (CSKY_32_IS_SUBU4 (x) || CSKY_16_IS_SUBU4 (x))
+
+/* mfcr rz, epsr.  */
+#define CSKY_32_IS_MFCR_EPSR(insn) ((insn & 0xffffffe0) == 0xc0026020)
+/* mfcr rz, fpsr.  */
+#define CSKY_32_IS_MFCR_FPSR(insn) ((insn & 0xffffffe0) == 0xc0036020)
+/* mfcr rz, epc.  */
+#define CSKY_32_IS_MFCR_EPC(insn) ((insn & 0xffffffe0) == 0xc0046020)
+/* mfcr rz, fpc.  */
+#define CSKY_32_IS_MFCR_FPC(insn) ((insn & 0xffffffe0) == 0xc0056020)
+
+#define CSKY_32_IS_RTE(insn) (insn == 0xc0004020)
+#define CSKY_32_IS_RFI(insn) (insn == 0xc0004420)
+#define CSKY_32_IS_JMP(insn) ((insn & 0xffe0ffff) == 0xe8c00000)
+#define CSKY_16_IS_JMP(insn) ((insn & 0xffc3) == 0x7800)
+#define CSKY_32_IS_JMPI(insn) ((insn & 0xffff0000) == 0xeac00000)
+#define CSKY_32_IS_JMPIX(insn) ((insn & 0xffe0fffc) == 0xe9e00000)
+#define CSKY_16_IS_JMPIX(insn) ((insn & 0xf8fc) == 0x38e0)
+
+#define CSKY_16_IS_BR(insn) ((insn & 0xfc00) == 0x0400)
+#define CSKY_32_IS_BR(insn) ((insn & 0xffff0000) == 0xe8000000)
+#define CSKY_16_IS_MOV_FP_SP(insn) (insn == 0x6e3b)     /* mov r8, r14.  */
+#define CSKY_32_IS_MOV_FP_SP(insn) (insn == 0xc40e4828) /* mov r8, r14.  */
+#define CSKY_16_IS_MOV_SP_FP(insn) (insn == 0x6fa3)     /* mov r14, r8.  */
+#define CSKY_32_INSN_MASK 0xc000
+#define CSKY_BKPT_INSN 0x0
+#define CSKY_NUM_GREGS 32
+/* 32 general regs + 4.  */
+#define CSKY_NUM_GREGS_SAVED_GREGS (CSKY_NUM_GREGS + 4)
+
+/* CSKY software bkpt write-mode.  */
+#define CSKY_WR_BKPT_MODE 4
+
+/* Define insns for parse rt_sigframe.  */
+/* There are three words(sig, pinfo, puc) before siginfo.  */
+#define CSKY_SIGINFO_OFFSET 0xc
+
+/* Size of struct siginfo.  */
+#define CSKY_SIGINFO_SIZE 0x80
+
+/* There are five words(uc_flags, uc_link, and three for uc_stack)
+   in struct ucontext before sigcontext.  */
+#define CSKY_UCONTEXT_SIGCONTEXT 0x14
+
+/* There is a word(sc_mask) before sc_usp.  */
+#define CSKY_SIGCONTEXT_SC_USP 0x4
+
+/* There is a word(sc_usp) before sc_a0.  */
+#define CSKY_SIGCONTEXT_SC_A0 0x4
+
+#define CSKY_MOVI_R7_173 0x00adea07
+#define CSKY_TRAP_0 0x2020c000
+
+#endif
--
2.11.0

Reply | Threaded
Open this post in threaded view
|

[2/2] C-SKY Port

Hafiz Abid Qadeer
In reply to this post by Hafiz Abid Qadeer
Mention csky target in the NEWS.

2018-07-25  Hafiz Abid Qadeer  <[hidden email]>

        * NEWS: Mention csky target.
---
 gdb/NEWS | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/gdb/NEWS b/gdb/NEWS
index 76b963e2bc..252e57ce88 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -34,6 +34,11 @@ thread apply [all | COUNT | -COUNT] [FLAG]... COMMAND
   FLAG arguments allow to control what output to produce and how to handle
   errors raised when applying COMMAND to a thread.

+* New targets
+
+CSKY ELF csky*-*-elf
+CSKY GNU/LINUX csky*-*-linux
+
 *** Changes in GDB 8.2

 * The 'set disassembler-options' command now supports specifying options
--
2.11.0

Reply | Threaded
Open this post in threaded view
|

Re: [2/2] C-SKY Port

Eli Zaretskii
> From: Hafiz Abid Qadeer <[hidden email]>
> CC: <[hidden email]>
> Date: Wed, 25 Jul 2018 11:55:32 +0100
>
> Mention csky target in the NEWS.
>
> 2018-07-25  Hafiz Abid Qadeer  <[hidden email]>
>
> * NEWS: Mention csky target.

OK for this part.
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Tom Tromey-2
In reply to this post by Hafiz Abid Qadeer
>>>>> ">" == Hafiz Abid Qadeer <[hidden email]> writes:

>> Add support for new target 'csky'.

>> 2018-07-25  Jiangshuai Li  <[hidden email]>
>>    Hafiz Abid Qadeer  <[hidden email]>
>>    Don Breazeal  <[hidden email]>

I didn't check the copyright assignment situation, but for a patch of
this size, assignments are needed.  I assume codesourcery has some kind
of blanket assignment, but what about Jiangshuai Li?

>> diff --git a/gdb/configure.tgt b/gdb/configure.tgt

>> +csky*-linux*)

>> +csky*-*)

It's more normal to mention all the "-"s, so "csky*-*-linux*" and "csky*-*-*".

I don't know anything about C-SKY, so I didn't really look deeply at the
arch-specific bits.  I assume those pass your testing.

>> diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c

>> +struct stack_item
>> +{
>> +  int len;
>> +  struct stack_item *prev;
>> +  void *data;

Seems to me that this could be gdb_byte instead of void here, and in
push_stack_item and pop_stack_item.

>> +/* Implement the push_dummy_call gdbarch method.  */
>> +
>> +static CORE_ADDR
>> +csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
>> +      struct regcache *regcache, CORE_ADDR bp_addr,
>> +      int nargs, struct value **args, CORE_ADDR sp,
>> +      int struct_return, CORE_ADDR struct_addr)
>> +{
[...]
>> +      arg_type = check_typedef (value_type (args[argnum]));
>> +      len = TYPE_LENGTH (arg_type);
>> +      val = value_contents (args[argnum]);

I wonder if this can ever throw.

In theory of course it can.  But maybe in practice it isn't possible?
I don't know.

The issue is, if it can throw, then the stack_items will be leaked.
A way around that is to redo the stack as self-managing C++ objects and
use a local std::vector or the like to hold them.

>> +  /* Transfer the dummy stack frame to the target.  */
>> +  while (si)
>> +    {
>> +      sp -= si->len;
>> +      write_memory (sp, (const bfd_byte *) si->data, si->len);

A similar consideration applies here.


This all seems pretty reasonable to me.

Tom
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Hafiz Abid Qadeer
Hi Tom,
Thanks for the review. Please see comments and updated patch below

On 27/07/18 16:49, Tom Tromey wrote:

>>>>>> ">" == Hafiz Abid Qadeer <[hidden email]> writes:
>
>>> Add support for new target 'csky'.
>
>>> 2018-07-25  Jiangshuai Li  <[hidden email]>
>>>    Hafiz Abid Qadeer  <[hidden email]>
>>>    Don Breazeal  <[hidden email]>
>
> I didn't check the copyright assignment situation, but for a patch of
> this size, assignments are needed.  I assume codesourcery has some kind
> of blanket assignment, but what about Jiangshuai Li?
Yes, csky aslo have a copyright assignment.

>
>>> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
>
>>> +csky*-linux*)
Done.

>
>>> +csky*-*)
Done.

>
> It's more normal to mention all the "-"s, so "csky*-*-linux*" and "csky*-*-*".
>
> I don't know anything about C-SKY, so I didn't really look deeply at the
> arch-specific bits.  I assume those pass your testing.
>
>>> diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
>
>>> +struct stack_item
>>> +{
>>> +  int len;
>>> +  struct stack_item *prev;
>>> +  void *data;
>
> Seems to me that this could be gdb_byte instead of void here, and in
> push_stack_item and pop_stack_item.
Done

>
>>> +/* Implement the push_dummy_call gdbarch method.  */
>>> +
>>> +static CORE_ADDR
>>> +csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
>>> +      struct regcache *regcache, CORE_ADDR bp_addr,
>>> +      int nargs, struct value **args, CORE_ADDR sp,
>>> +      int struct_return, CORE_ADDR struct_addr)
>>> +{
> [...]
>>> +      arg_type = check_typedef (value_type (args[argnum]));
>>> +      len = TYPE_LENGTH (arg_type);
>>> +      val = value_contents (args[argnum]);
>
> I wonder if this can ever throw.
>
> In theory of course it can.  But maybe in practice it isn't possible?
> I don't know.
>
> The issue is, if it can throw, then the stack_items will be leaked.
> A way around that is to redo the stack as self-managing C++ objects and
> use a local std::vector or the like to hold them.
>
>>> +  /* Transfer the dummy stack frame to the target.  */
>>> +  while (si)
>>> +    {
>>> +      sp -= si->len;
>>> +      write_memory (sp, (const bfd_byte *) si->data, si->len);
>
> A similar consideration applies here.
I removed the push/pull_stack_item and instead introduced a vector as
you suggested.
>
>
> This all seems pretty reasonable to me.
If it is approved, is there any chance that patch can make it to 8.2
release?

Thanks,
Abid



--
2018-07-27  Jiangshuai Li  <[hidden email]>
            Hafiz Abid Qadeer  <[hidden email]>
            Don Breazeal  <[hidden email]>

        * csky-linux-tdep.c: New file.
        * csky-tdep.c: Likewise.
        * csky-tdep.h: Likewise.
        * Makefile.in (ALL_TARGET_OBS): Add csky-linux-tdep.o and
        csky-tdep.o.
        (HFILES_NO_SRCDIR): Add csky-tdep.h.
        (ALLDEPFILES): Add csky-linux-tdep.c and csky-tdep.c
        * configure.tgt: Add csky support.
---
 gdb/Makefile.in       |    5 +
 gdb/configure.tgt     |   11 +
 gdb/csky-linux-tdep.c |  263 ++++++
 gdb/csky-tdep.c       | 2307
+++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/csky-tdep.h       |  355 ++++++++
 5 files changed, 2941 insertions(+)
 create mode 100644 gdb/csky-linux-tdep.c
 create mode 100644 gdb/csky-tdep.c
 create mode 100644 gdb/csky-tdep.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8c744d70c0..9eb420f250 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -688,6 +688,8 @@ ALL_TARGET_OBS = \
  bsd-uthread.o \
  cris-linux-tdep.o \
  cris-tdep.o \
+ csky-linux-tdep.o \
+ csky-tdep.o \
  dicos-tdep.o \
  fbsd-tdep.o \
  frv-linux-tdep.o \
@@ -1207,6 +1209,7 @@ HFILES_NO_SRCDIR = \
  completer.h \
  cp-abi.h \
  cp-support.h \
+ csky-tdep.h \
  ctf.h \
  d-lang.h \
  darwin-nat.h \
@@ -2207,6 +2210,8 @@ ALLDEPFILES = \
  bfin-tdep.c \
  bsd-kvm.c \
  bsd-uthread.c \
+ csky-linux-tdep.c \
+ csky-tdep.c \
  darwin-nat.c \
  dicos-tdep.c \
  fbsd-nat.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index f197160896..d2cd20dbcd 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -206,6 +206,17 @@ cris*)
  gdb_target_obs="cris-tdep.o cris-linux-tdep.o linux-tdep.o solib-svr4.o"
  ;;

+csky*-*-linux*)
+ # Target: CSKY running GNU/Linux
+ gdb_target_obs="csky-tdep.o csky-linux-tdep.o glibc-tdep.o \
+ linux-tdep.o solib-svr4.o"
+ ;;
+
+csky*-*-*)
+ # Target: CSKY bare metal
+ gdb_target_obs="csky-tdep.o"
+ ;;
+
 frv-*-*)
  # Target: Fujitsu FRV processor
  gdb_target_obs="frv-tdep.o frv-linux-tdep.o linux-tdep.o solib-frv.o"
diff --git a/gdb/csky-linux-tdep.c b/gdb/csky-linux-tdep.c
new file mode 100644
index 0000000000..9e3ec393c8
--- /dev/null
+++ b/gdb/csky-linux-tdep.c
@@ -0,0 +1,263 @@
+/* Target-dependent code for GNU/Linux on CSKY.
+
+   Copyright (C) 2012-2018 Free Software Foundation, Inc.
+
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   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 "osabi.h"
+#include "glibc-tdep.h"
+#include "linux-tdep.h"
+#include "gdbarch.h"
+#include "solib-svr4.h"
+#include "regset.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+#include "csky-tdep.h"
+
+/* Functions, definitions, and data structures for C-Sky core file
debug.  */
+
+/* General regset pc, r1, r0, psr, r2-r31 for CK810.  */
+#define SIZEOF_CSKY_GREGSET 34*4
+/* Float regset fesr fsr fr0-fr31 for CK810.  */
+#define SIZEOF_CSKY_FREGSET 34*4
+
+/* Offset mapping table from core_section to regcache of general
+   registers for ck810.  */
+static const int csky_gregset_offset[] =
+{
+  72,  1,  0, 89,  2,  /* pc, r1, r0, psr, r2.  */
+   3,  4,  5,  6,  7,  /* r3 ~ r32.  */
+   8,  9, 10, 11, 12,
+  13, 14, 15, 16, 17,
+  18, 19, 20, 21, 22,
+  23, 24, 25, 26, 27,
+  28, 29, 30, 31
+};
+
+/* Offset mapping table from core_section to regcache of float
+   registers for ck810.  */
+
+static const int csky_fregset_offset[] =
+{
+  122, 123, 40, 41, 42,     /* fcr, fesr, fr0 ~ fr2.  */
+   43,  44, 45, 46, 47,     /* fr3 ~ fr15.  */
+   48,  49, 50, 51, 52,
+   53,  54, 55
+};
+
+/* Implement the supply_regset hook for GP registers in core files.  */
+
+static void
+csky_supply_gregset (const struct regset *regset,
+     struct regcache *regcache, int regnum,
+     const void *regs, size_t len)
+{
+  int i, gregset_num;
+  const gdb_byte *gregs = (const gdb_byte *) regs ;
+
+  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
+  gregset_num = ARRAY_SIZE (csky_gregset_offset);
+
+  for (i = 0; i < gregset_num; i++)
+    {
+      if ((regnum == csky_gregset_offset[i] || regnum == -1)
+  && csky_gregset_offset[i] != -1)
+ regcache->raw_supply (csky_gregset_offset[i], gregs + 4 * i);
+    }
+}
+
+/* Implement the collect_regset hook for GP registers in core files.  */
+
+static void
+csky_collect_gregset (const struct regset *regset,
+      const struct regcache *regcache,
+      int regnum, void *gregs_buf, size_t len)
+{
+  int regno, gregset_num;
+  gdb_byte *gregs = (gdb_byte *) gregs_buf ;
+
+  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
+  gregset_num = ARRAY_SIZE (csky_gregset_offset);
+
+  for (regno = 0; regno < gregset_num; regno++)
+    {
+      if ((regnum == csky_gregset_offset[regno] || regnum == -1)
+  && csky_gregset_offset[regno] != -1)
+ regcache->raw_collect (regno,
+       gregs + 4 + csky_gregset_offset[regno]);
+    }
+}
+
+/* Implement the supply_regset hook for FP registers in core files.  */
+
+void
+csky_supply_fregset (const struct regset *regset,
+     struct regcache *regcache, int regnum,
+     const void *regs, size_t len)
+{
+  int i;
+  int offset = 0;
+  struct gdbarch *gdbarch = regcache->arch ();
+  const gdb_byte *fregs = (const gdb_byte *) regs;
+  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
+
+  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
+  for (i = 0; i < fregset_num; i++)
+    {
+      if ((regnum == csky_fregset_offset[i] || regnum == -1)
+  && csky_fregset_offset[i] != -1)
+ {
+  int num = csky_fregset_offset[i];
+  offset += register_size (gdbarch, num);
+  regcache->raw_supply (csky_fregset_offset[i], fregs + offset);
+ }
+    }
+}
+
+/* Implement the collect_regset hook for FP registers in core files.  */
+
+static void
+csky_collect_fregset (const struct regset *regset,
+      const struct regcache *regcache,
+      int regnum, void *fregs_buf, size_t len)
+{
+  int regno;
+  struct gdbarch *gdbarch = regcache->arch ();
+  gdb_byte *fregs = (gdb_byte *) fregs_buf ;
+  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
+  int offset = 0;
+
+  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
+  for (regno = 0; regno < fregset_num; regno++)
+    {
+      if ((regnum == csky_fregset_offset[regno] || regnum == -1)
+  && csky_fregset_offset[regno] != -1)
+ {
+  offset += register_size (gdbarch, csky_fregset_offset[regno]);
+  regcache->raw_collect (regno, fregs + offset);
+ }
+    }
+}
+
+static const struct regset csky_regset_general =
+{
+  NULL,
+  csky_supply_gregset,
+  csky_collect_gregset
+};
+
+static const struct regset csky_regset_float =
+{
+  NULL,
+  csky_supply_fregset,
+  csky_collect_fregset
+};
+
+/* Iterate over core file register note sections.  */
+
+static void
+csky_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
+{
+  cb (".reg", sizeof (csky_gregset_offset), &csky_regset_general,
+      NULL, cb_data);
+  cb (".reg2", sizeof (csky_fregset_offset), &csky_regset_float,
+      NULL, cb_data);
+}
+
+static void
+csky_linux_rt_sigreturn_init (const struct tramp_frame *self,
+      struct frame_info *this_frame,
+      struct trad_frame_cache *this_cache,
+      CORE_ADDR func)
+{
+  int i;
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, 14);
+
+  CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE
+   + CSKY_UCONTEXT_SIGCONTEXT
+   + CSKY_SIGCONTEXT_SC_USP
+   + CSKY_SIGCONTEXT_SC_A0;
+
+  /* Set addrs of R0 ~ R13.  */
+  for (i = 0; i < 14; i++)
+   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
+
+  /* Set addrs of SP(R14) and R15.  */
+  trad_frame_set_reg_addr (this_cache, 14, base - 4);
+  trad_frame_set_reg_addr (this_cache, 15, base + 4 * 14);
+
+  /* Set addrs of R16 ~ R31.  */
+  for (i = 15; i < 31; i++)
+   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
+
+  /* Set addrs of PSR and PC.  */
+  trad_frame_set_reg_addr (this_cache, 89, base + 4 * 33);
+  trad_frame_set_reg_addr (this_cache, 72, base + 4 * 34);
+
+  trad_frame_set_id (this_cache, frame_id_build (sp, func));
+}
+
+static struct tramp_frame
+csky_linux_rt_sigreturn_tramp_frame = {
+  SIGTRAMP_FRAME,
+  4,
+  {
+    { CSKY_MOVI_R7_173, -1 },
+    { CSKY_TRAP_0, -1 },
+    { TRAMP_SENTINEL_INSN }
+  },
+  csky_linux_rt_sigreturn_init
+};
+
+/* Hook function for gdbarch_register_osabi.  */
+
+static void
+csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  linux_init_abi (info, gdbarch);
+
+  /* Shared library handling.  */
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+
+  /* Enable TLS support.  */
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+     svr4_fetch_objfile_link_map);
+
+  /* Core file support.  */
+  set_gdbarch_iterate_over_regset_sections (
+    gdbarch, csky_linux_iterate_over_regset_sections);
+
+  /* Append tramp frame unwinder for SIGNAL.  */
+
+  tramp_frame_prepend_unwinder (gdbarch,
+ &csky_linux_rt_sigreturn_tramp_frame);
+}
+
+void
+_initialize_csky_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_csky, 0, GDB_OSABI_LINUX,
+  csky_linux_init_abi);
+}
diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
new file mode 100644
index 0000000000..4ddadc7885
--- /dev/null
+++ b/gdb/csky-tdep.c
@@ -0,0 +1,2307 @@
+/* Target-dependent code for the CSKY architecture, for GDB.
+
+   Copyright (C) 2010-2018 Free Software Foundation, Inc.
+
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   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 "gdb_assert.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "block.h"
+#include "reggroups.h"
+#include "elf/csky.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "dis-asm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "infcall.h"
+#include "floatformat.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "dwarf2-frame.h"
+#include "user-regs.h"
+#include "valprint.h"
+#include "reggroups.h"
+#include "csky-tdep.h"
+#include "regset.h"
+#include "block.h"
+#include "opcode/csky.h"
+#include <algorithm>
+#include <vector>
+
+/* Control debugging information emitted in this file.  */
+static int csky_debug = 0;
+
+static struct reggroup *cr_reggroup;
+static struct reggroup *fr_reggroup;
+static struct reggroup *vr_reggroup;
+static struct reggroup *mmu_reggroup;
+static struct reggroup *prof_reggroup;
+
+/* Convenience function to print debug messages in prologue analysis.  */
+
+static void
+print_savedreg_msg (int regno, int offsets[], bool print_continuing)
+{
+  fprintf_unfiltered (gdb_stdlog, "csky: r%d saved at offset 0x%x\n",
+      regno, offsets[regno]);
+  if (print_continuing)
+    fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+}
+
+/*  Check whether the instruction at ADDR is 16-bit or not.  */
+
+static int
+csky_pc_is_csky16 (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_byte target_mem[2];
+  int status;
+  unsigned int insn;
+  int ret = 1;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  status = target_read_memory (addr, target_mem, 2);
+  /* Assume a 16-bit instruction if we can't read memory.  */
+  if (status)
+    return 1;
+
+  /* Get instruction from memory.  */
+  insn = extract_unsigned_integer (target_mem, 2, byte_order);
+  if ((insn & CSKY_32_INSN_MASK) == CSKY_32_INSN_MASK)
+    ret = 0;
+  else if (insn == CSKY_BKPT_INSN)
+    {
+      /* Check for 32-bit bkpt instruction which is all 0.  */
+      status = target_read_memory (addr + 2, target_mem, 2);
+      if (status)
+ return 1;
+
+      insn = extract_unsigned_integer (target_mem, 2, byte_order);
+      if (insn == CSKY_BKPT_INSN)
+ ret = 0;
+    }
+  return ret;
+}
+
+/* Get one instruction at ADDR and store it in INSN.  Return 2 for
+   a 16-bit instruction or 4 for a 32-bit instruction.  */
+
+static int
+csky_get_insn (struct gdbarch *gdbarch, CORE_ADDR addr, unsigned int *insn)
+{
+  gdb_byte target_mem[2];
+  unsigned int insn_type;
+  int status;
+  int insn_len = 2;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  status = target_read_memory (addr, target_mem, 2);
+  if (status)
+    memory_error (TARGET_XFER_E_IO, addr);
+
+  insn_type = extract_unsigned_integer (target_mem, 2, byte_order);
+  if (CSKY_32_INSN_MASK == (insn_type & CSKY_32_INSN_MASK))
+    {
+      status = target_read_memory (addr + 2, target_mem, 2);
+      if (status)
+ memory_error (TARGET_XFER_E_IO, addr);
+      insn_type = ((insn_type << 16)
+   | extract_unsigned_integer (target_mem, 2, byte_order));
+      insn_len = 4;
+    }
+  *insn = insn_type;
+  return insn_len;
+}
+
+/* Implement the read_pc gdbarch method.  */
+
+static CORE_ADDR
+csky_read_pc (readable_regcache *regcache)
+{
+  ULONGEST pc;
+  regcache->cooked_read (CSKY_PC_REGNUM, &pc);
+  return pc;
+}
+
+/* Implement the write_pc gdbarch method.  */
+
+static void
+csky_write_pc (regcache *regcache, CORE_ADDR val)
+{
+  regcache_cooked_write_unsigned (regcache, CSKY_PC_REGNUM, val);
+}
+
+/* Implement the unwind_sp gdbarch method.  */
+
+static CORE_ADDR
+csky_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, CSKY_SP_REGNUM);
+}
+
+/* C-Sky ABI register names.  */
+
+static const char *csky_register_names[] =
+{
+  /* General registers 0 - 31.  */
+  "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+  "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+
+  /* DSP hilo registers 36 and 37.  */
+  "",      "",    "",     "",     "hi",    "lo",   "",    "",
+
+  /* FPU/VPU general registers 40 - 71.  */
+  "fr0", "fr1", "fr2",  "fr3",  "fr4",  "fr5",  "fr6",  "fr7",
+  "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+  "vr0", "vr1", "vr2",  "vr3",  "vr4",  "vr5",  "vr6",  "vr7",
+  "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15",
+
+  /* Program counter 72.  */
+  "pc",
+
+  /* Optional registers (ar) 73 - 88.  */
+  "ar0", "ar1", "ar2",  "ar3",  "ar4",  "ar5",  "ar6",  "ar7",
+  "ar8", "ar9", "ar10", "ar11", "ar12", "ar13", "ar14", "ar15",
+
+  /* Control registers (cr) 89 - 119.  */
+  "psr",  "vbr",  "epsr", "fpsr", "epc",  "fpc",  "ss0",  "ss1",
+  "ss2",  "ss3",  "ss4",  "gcr",  "gsr",  "cr13", "cr14", "cr15",
+  "cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
+  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
+
+  /* FPU/VPU control registers 121 ~ 123.  */
+  /* User sp 127.  */
+  "fid", "fcr", "fesr", "", "", "", "usp",
+
+  /* MMU control registers: 128 - 136.  */
+  "mcr0", "mcr2", "mcr3", "mcr4", "mcr6", "mcr8", "mcr29", "mcr30",
+  "mcr31", "", "", "",
+
+  /* Profiling control registers 140 - 143.  */
+  /* Profiling software general registers 144 - 157.  */
+  "profcr0",  "profcr1",  "profcr2",  "profcr3",  "profsgr0",  "profsgr1",
+  "profsgr2", "profsgr3", "profsgr4", "profsgr5", "profsgr6",  "profsgr7",
+  "profsgr8", "profsgr9", "profsgr10","profsgr11","profsgr12", "profsgr13",
+  "", "",
+
+  /* Profiling architecture general registers 160 - 174.  */
+  "profagr0", "profagr1", "profagr2", "profagr3", "profagr4", "profagr5",
+  "profagr6", "profagr7", "profagr8", "profagr9", "profagr10","profagr11",
+  "profagr12","profagr13","profagr14", "",
+
+  /* Profiling extension general registers 176 - 188.  */
+  "profxgr0", "profxgr1", "profxgr2", "profxgr3", "profxgr4", "profxgr5",
+  "profxgr6", "profxgr7", "profxgr8", "profxgr9", "profxgr10","profxgr11",
+  "profxgr12",
+
+  /* Control registers in bank1.  */
+  "", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", "",
+  "cp1cr16", "cp1cr17", "cp1cr18", "cp1cr19", "cp1cr20", "", "", "",
+  "", "", "", "", "", "", "", "",
+
+  /* Control registers in bank3 (ICE).  */
+  "sepsr", "sevbr", "seepsr", "", "seepc", "", "nsssp", "seusp",
+  "sedcr", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", ""
+};
+
+/* Implement the register_name gdbarch method.  */
+
+static const char *
+csky_register_name (struct gdbarch *gdbarch, int reg_nr)
+{
+  int csky_total_regnum;
+
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return tdesc_register_name (gdbarch, reg_nr);
+
+  if (reg_nr < 0)
+    return NULL;
+
+  if (reg_nr >= gdbarch_num_regs (gdbarch))
+    return NULL;
+
+  return csky_register_names[reg_nr];
+}
+
+/* Construct vector type for vrx registers.  */
+
+static struct type *
+csky_vector_type (struct gdbarch *gdbarch)
+{
+  const struct builtin_type *bt = builtin_type (gdbarch);
+
+  struct type *t;
+
+  t = arch_composite_type (gdbarch, "__gdb_builtin_type_vec128i",
+   TYPE_CODE_UNION);
+
+  append_composite_type_field (t, "u32",
+       init_vector_type (bt->builtin_int32, 4));
+  append_composite_type_field (t, "u16",
+       init_vector_type (bt->builtin_int16, 8));
+  append_composite_type_field (t, "u8",
+       init_vector_type (bt->builtin_int8, 16));
+
+  TYPE_VECTOR (t) = 1;
+  TYPE_NAME (t) = "builtin_type_vec128i";
+
+  return t;
+}
+
+/* Return the GDB type object for the "standard" data type
+   of data in register N.  */
+
+static struct type *
+csky_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+  int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
+
+  /* PC, EPC, FPC is a text pointer.  */
+  if ((reg_nr == CSKY_PC_REGNUM)  || (reg_nr == CSKY_EPC_REGNUM)
+      || (reg_nr == CSKY_FPC_REGNUM))
+    return builtin_type (gdbarch)->builtin_func_ptr;
+
+  /* VBR is a data pointer.  */
+  if (reg_nr == CSKY_VBR_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+
+  /* Float register has 64 bits, and only in ck810.  */
+  if ((reg_nr >=CSKY_FR0_REGNUM) && (reg_nr <= CSKY_FR0_REGNUM + 15))
+      return arch_float_type (gdbarch, 64, "builtin_type_csky_ext",
+      floatformats_ieee_double);
+
+  /* Vector register has 128 bits, and only in ck810.  */
+  if ((reg_nr >= CSKY_VR0_REGNUM) && (reg_nr <= CSKY_VR0_REGNUM + 15))
+    return csky_vector_type (gdbarch);
+
+  /* Profiling general register has 48 bits, we use 64bit.  */
+  if ((reg_nr >= CSKY_PROFGR_REGNUM) && (reg_nr <= CSKY_PROFGR_REGNUM +
44))
+    return builtin_type (gdbarch)->builtin_uint64;
+
+  if (reg_nr == CSKY_SP_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+
+  /* Others are 32 bits.  */
+  return builtin_type (gdbarch)->builtin_int32;
+}
+
+/* Data structure to marshall items in a dummy stack frame when
+   calling a function in the inferior.  */
+
+struct stack_item
+{
+  stack_item (int len_, const gdb_byte *data_)
+  : len (len_), data (data_)
+  {}
+
+  int len;
+  const gdb_byte *data;
+};
+
+/* Implement the push_dummy_call gdbarch method.  */
+
+static CORE_ADDR
+csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+      struct regcache *regcache, CORE_ADDR bp_addr,
+      int nargs, struct value **args, CORE_ADDR sp,
+      int struct_return, CORE_ADDR struct_addr)
+{
+  int argnum;
+  int argreg = CSKY_ABI_A0_REGNUM;
+  int last_arg_regnum = CSKY_ABI_LAST_ARG_REGNUM;
+  int need_dummy_stack = 0;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  std::vector<stack_item> stack_items;
+
+  /* Set the return address.  For CSKY, the return breakpoint is
+     always at BP_ADDR.  */
+  regcache_cooked_write_unsigned (regcache, CSKY_LR_REGNUM, bp_addr);
+
+  /* The struct_return pointer occupies the first parameter
+     passing register.  */
+  if (struct_return)
+    {
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: struct return in %s = %s\n",
+      gdbarch_register_name (gdbarch, argreg),
+      paddress (gdbarch, struct_addr));
+ }
+      regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
+      argreg++;
+    }
+
+  /* Put parameters into argument registers in REGCACHE.
+     In ABI argument registers are r0 through r3.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      int len;
+      struct type *arg_type;
+      const gdb_byte *val;
+
+      arg_type = check_typedef (value_type (args[argnum]));
+      len = TYPE_LENGTH (arg_type);
+      val = value_contents (args[argnum]);
+
+      /* Copy the argument to argument registers or the dummy stack.
+ Large arguments are split between registers and stack.
+
+ If len < 4, there is no need to worry about endianness since
+ the arguments will always be stored in the low address.  */
+      if (len < 4)
+ {
+  CORE_ADDR regval
+    = extract_unsigned_integer (val, len, byte_order);
+  regcache_cooked_write_unsigned (regcache, argreg, regval);
+  argreg++;
+ }
+      else
+ {
+  while (len > 0)
+    {
+      int partial_len = len < 4 ? len : 4;
+      if (argreg <= last_arg_regnum)
+ {
+  /* The argument is passed in an argument register.  */
+  CORE_ADDR regval
+    = extract_unsigned_integer (val, partial_len,
+ byte_order);
+  if (byte_order == BFD_ENDIAN_BIG)
+    regval <<= (4 - partial_len) * 8;
+
+  /* Put regval into register in REGCACHE.  */
+  regcache_cooked_write_unsigned (regcache, argreg,
+  regval);
+  argreg++;
+ }
+      else
+ {
+  /* The argument should be pushed onto the dummy stack.  */
+  stack_items.emplace_back (4, val);
+  need_dummy_stack += 4;
+ }
+      len -= partial_len;
+      val += partial_len;
+    }
+ }
+    }
+
+  /* Transfer the dummy stack frame to the target.  */
+  std::vector<stack_item>::reverse_iterator iter;
+  for (iter = stack_items.rbegin (); iter != stack_items.rend (); ++iter)
+    {
+      sp -= iter->len;
+      write_memory (sp, iter->data, iter->len);
+    }
+
+  /* Finally, update the SP register.  */
+  regcache_cooked_write_unsigned (regcache, CSKY_SP_REGNUM, sp);
+  return sp;
+}
+
+/* Implement the return_value gdbarch method.  */
+
+static enum return_value_convention
+csky_return_value (struct gdbarch *gdbarch, struct value *function,
+   struct type *valtype, struct regcache *regcache,
+   gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  CORE_ADDR regval;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int len = TYPE_LENGTH (valtype);
+  unsigned int ret_regnum = CSKY_RET_REGNUM;
+
+  /* Csky abi specifies that return values larger than 8 bytes
+     are put on the stack.  */
+  if (len > 8)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+  else
+    {
+      if (readbuf != NULL)
+ {
+  ULONGEST tmp;
+  /* By using store_unsigned_integer we avoid having to do
+     anything special for small big-endian values.  */
+  regcache->cooked_read (ret_regnum, &tmp);
+  store_unsigned_integer (readbuf, (len > 4 ? 4 : len),
+  byte_order, tmp);
+  if (len > 4)
+    {
+      regcache->cooked_read (ret_regnum + 1, &tmp);
+      store_unsigned_integer (readbuf + 4,  4, byte_order, tmp);
+    }
+ }
+      if (writebuf != NULL)
+ {
+  regval = extract_unsigned_integer (writebuf, len > 4 ? 4 : len,
+     byte_order);
+  regcache_cooked_write_unsigned (regcache, ret_regnum, regval);
+  if (len > 4)
+    {
+      regval = extract_unsigned_integer ((gdb_byte *) writebuf + 4,
+ 4, byte_order);
+      regcache_cooked_write_unsigned (regcache, ret_regnum + 1,
+      regval);
+    }
+
+ }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Implement the frame_align gdbarch method.
+
+   Adjust the address downward (direction of stack growth) so that it
+   is correctly aligned for a new stack frame.  */
+
+static CORE_ADDR
+csky_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 4);
+}
+
+/* Unwind cache used for gdbarch fallback unwinder.  */
+
+struct csky_unwind_cache
+{
+  /* The stack pointer at the time this frame was created; i.e. the
+     caller's stack pointer when this function was called.  It is used
+     to identify this frame.  */
+  CORE_ADDR prev_sp;
+
+  /* The frame base for this frame is just prev_sp - frame size.
+     FRAMESIZE is the distance from the frame pointer to the
+     initial stack pointer.  */
+  int framesize;
+
+  /* The register used to hold the frame pointer for this frame.  */
+  int framereg;
+
+  /* Saved register offsets.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Do prologue analysis, returning the PC of the first instruction
+   after the function prologue.  */
+
+static CORE_ADDR
+csky_analyze_prologue (struct gdbarch *gdbarch,
+       CORE_ADDR start_pc,
+       CORE_ADDR limit_pc,
+       CORE_ADDR end_pc,
+       struct frame_info *this_frame,
+       struct csky_unwind_cache *this_cache,
+       lr_type_t lr_type)
+{
+  CORE_ADDR addr;
+  CORE_ADDR sp;
+  CORE_ADDR stack_size;
+  unsigned int insn, rn;
+  int status;
+  int flags;
+  int framesize = 0;
+  int stacksize = 0;
+  int register_offsets[CSKY_NUM_GREGS_SAVED_GREGS];
+  int insn_len;
+  /* For adjusting fp.  */
+  int is_fp_saved = 0;
+  int adjust_fp = 0;
+
+  /* REGISTER_OFFSETS will contain offsets from the top of the frame
+     (NOT the frame pointer) for the various saved registers, or -1
+     if the register is not saved.  */
+  for (rn = 0; rn < CSKY_NUM_GREGS_SAVED_GREGS; rn++)
+    register_offsets[rn] = -1;
+
+  /* Analyze the prologue.  Things we determine from analyzing the
+     prologue include the size of the frame and which registers are
+     saved (and where).  */
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: Scanning prologue: start_pc = 0x%x,"
+  "limit_pc = 0x%x\n", (unsigned int) start_pc,
+  (unsigned int) limit_pc);
+    }
+
+  /* Default to 16 bit instruction.  */
+  insn_len = 2;
+  stacksize = 0;
+  for (addr = start_pc; addr < limit_pc; addr += insn_len)
+    {
+      /* Get next insn.  */
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+
+      /* Check if 32 bit.  */
+      if (insn_len == 4)
+ {
+  /* subi32 sp,sp oimm12.  */
+  if (CSKY_32_IS_SUBI0 (insn))
+    {
+      /* Got oimm12.  */
+      int offset = CSKY_32_SUBI_IMM (insn);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: got subi sp,%d; continuing\n",
+      offset);
+ }
+      stacksize += offset;
+      continue;
+    }
+  /* stm32 ry-rz,(sp).  */
+  else if (CSKY_32_IS_STMx0 (insn))
+    {
+      /* Spill register(s).  */
+      int start_register;
+      int reg_count;
+      int offset;
+
+      /* BIG WARNING! The CKCore ABI does not restrict functions
+ to taking only one stack allocation.  Therefore, when
+ we save a register, we record the offset of where it was
+ saved relative to the current stacksize.  This will
+ then give an offset from the SP upon entry to our
+ function.  Remember, stacksize is NOT constant until
+ we're done scanning the prologue.  */
+      start_register = CSKY_32_STM_VAL_REGNUM (insn);
+      reg_count = CSKY_32_STM_SIZE (insn);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: got stm r%d-r%d,(sp)\n",
+      start_register,
+      start_register + reg_count);
+ }
+
+      for (rn = start_register, offset = 0;
+   rn <= start_register + reg_count;
+   rn++, offset += 4)
+ {
+  register_offsets[rn] = stacksize - offset;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: r%d saved at 0x%x"
+  " (offset %d)\n",
+  rn, register_offsets[rn],
+  offset);
+    }
+ }
+      if (csky_debug)
+ fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+      continue;
+    }
+  /* stw ry,(sp,disp).  */
+  else if (CSKY_32_IS_STWx0 (insn))
+    {
+      /* Spill register: see note for IS_STM above.  */
+      int disp;
+
+      rn = CSKY_32_ST_VAL_REGNUM (insn);
+      disp = CSKY_32_ST_OFFSET (insn);
+      register_offsets[rn] = stacksize - disp;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  else if (CSKY_32_IS_MOV_FP_SP (insn))
+    {
+      /* SP is saved to FP reg, means code afer prologue may
+ modify SP.  */
+      is_fp_saved = 1;
+      adjust_fp = stacksize;
+      continue;
+    }
+  else if (CSKY_32_IS_MFCR_EPSR (insn))
+    {
+      unsigned int insn2;
+      addr += 4;
+      int mfcr_regnum = insn & 0x1f;
+      insn_len = csky_get_insn (gdbarch, addr, &insn2);
+      if (insn_len == 2)
+ {
+  int stw_regnum = (insn2 >> 5) & 0x7;
+  if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_EPSR_REGNUM.  */
+      rn  = CSKY_NUM_GREGS;
+      offset = CSKY_16_STWx0_OFFSET (insn2);
+      register_offsets[rn] = stacksize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+      else
+ {
+  /* INSN_LEN == 4.  */
+  int stw_regnum = (insn2 >> 21) & 0x1f;
+  if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_EPSR_REGNUM.  */
+      rn  = CSKY_NUM_GREGS;
+      offset = CSKY_32_ST_OFFSET (insn2);
+      register_offsets[rn] = framesize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+    }
+  else if (CSKY_32_IS_MFCR_FPSR (insn))
+    {
+      unsigned int insn2;
+      addr += 4;
+      int mfcr_regnum = insn & 0x1f;
+      insn_len = csky_get_insn (gdbarch, addr, &insn2);
+      if (insn_len == 2)
+ {
+  int stw_regnum = (insn2 >> 5) & 0x7;
+  if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum
+ == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_FPSR_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 1;
+      offset = CSKY_16_STWx0_OFFSET (insn2);
+      register_offsets[rn] = stacksize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+      else
+ {
+  /* INSN_LEN == 4.  */
+  int stw_regnum = (insn2 >> 21) & 0x1f;
+  if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_FPSR_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 1;
+      offset = CSKY_32_ST_OFFSET (insn2);
+      register_offsets[rn] = framesize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+    }
+  else if (CSKY_32_IS_MFCR_EPC (insn))
+    {
+      unsigned int insn2;
+      addr += 4;
+      int mfcr_regnum = insn & 0x1f;
+      insn_len = csky_get_insn (gdbarch, addr, &insn2);
+      if (insn_len == 2)
+ {
+  int stw_regnum = (insn2 >> 5) & 0x7;
+  if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_EPC_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 2;
+      offset = CSKY_16_STWx0_OFFSET (insn2);
+      register_offsets[rn] = stacksize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+      else
+ {
+  /* INSN_LEN == 4.  */
+  int stw_regnum = (insn2 >> 21) & 0x1f;
+  if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_EPC_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 2;
+      offset = CSKY_32_ST_OFFSET (insn2);
+      register_offsets[rn] = framesize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+    }
+  else if (CSKY_32_IS_MFCR_FPC (insn))
+    {
+      unsigned int insn2;
+      addr += 4;
+      int mfcr_regnum = insn & 0x1f;
+      insn_len = csky_get_insn (gdbarch, addr, &insn2);
+      if (insn_len == 2)
+ {
+  int stw_regnum = (insn2 >> 5) & 0x7;
+  if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_FPC_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 3;
+      offset = CSKY_16_STWx0_OFFSET (insn2);
+      register_offsets[rn] = stacksize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+      else
+ {
+  /* INSN_LEN == 4.  */
+  int stw_regnum = (insn2 >> 21) & 0x1f;
+  if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+    {
+      int offset;
+
+      /* CSKY_FPC_REGNUM.  */
+      rn  = CSKY_NUM_GREGS + 3;
+      offset = CSKY_32_ST_OFFSET (insn2);
+      register_offsets[rn] = framesize - offset;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  break;
+ }
+    }
+  else if (CSKY_32_IS_PUSH (insn))
+    {
+      /* Push for 32_bit.  */
+      int offset = 0;
+      if (CSKY_32_IS_PUSH_R29 (insn))
+ {
+  stacksize += 4;
+  register_offsets[29] = stacksize;
+  if (csky_debug)
+    print_savedreg_msg (29, register_offsets, false);
+  offset += 4;
+ }
+      if (CSKY_32_PUSH_LIST2 (insn))
+ {
+  int num = CSKY_32_PUSH_LIST2 (insn);
+  int tmp = 0;
+  stacksize += num * 4;
+  offset += num * 4;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: push regs_array: r16-r%d\n",
+  16 + num - 1);
+    }
+  for (rn = 16; rn <= 16 + num - 1; rn++)
+    {
+       register_offsets[rn] = stacksize - tmp;
+       if (csky_debug)
+ {
+   fprintf_unfiltered (gdb_stdlog,
+       "csky: r%d saved at 0x%x"
+       " (offset %d)\n", rn,
+       register_offsets[rn], tmp);
+ }
+       tmp += 4;
+    }
+ }
+      if (CSKY_32_IS_PUSH_R15 (insn))
+ {
+  stacksize += 4;
+  register_offsets[15] = stacksize;
+  if (csky_debug)
+    print_savedreg_msg (15, register_offsets, false);
+  offset += 4;
+ }
+      if (CSKY_32_PUSH_LIST1 (insn))
+ {
+  int num = CSKY_32_PUSH_LIST1 (insn);
+  int tmp = 0;
+  stacksize += num * 4;
+  offset += num * 4;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: push regs_array: r4-r%d\n",
+  4 + num - 1);
+    }
+  for (rn = 4; rn <= 4 + num - 1; rn++)
+    {
+       register_offsets[rn] = stacksize - tmp;
+       if (csky_debug)
+ {
+   fprintf_unfiltered (gdb_stdlog,
+       "csky: r%d saved at 0x%x"
+       " (offset %d)\n", rn,
+       register_offsets[rn], tmp);
+ }
+ tmp += 4;
+    }
+ }
+
+      framesize = stacksize;
+      if (csky_debug)
+ fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+      continue;
+    }
+  else if (CSKY_32_IS_LRW4 (insn) || CSKY_32_IS_MOVI4 (insn)
+   || CSKY_32_IS_MOVIH4 (insn) || CSKY_32_IS_BMASKI4 (insn))
+    {
+      int adjust = 0;
+      int offset = 0;
+      unsigned int insn2;
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: looking at large frame\n");
+ }
+      if (CSKY_32_IS_LRW4 (insn))
+ {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int literal_addr = (addr + ((insn & 0xffff) << 2))
+     & 0xfffffffc;
+  adjust = read_memory_unsigned_integer (literal_addr, 4,
+ byte_order);
+ }
+      else if (CSKY_32_IS_MOVI4 (insn))
+ adjust = (insn  & 0xffff);
+      else if (CSKY_32_IS_MOVIH4 (insn))
+ adjust = (insn & 0xffff) << 16;
+      else
+ {
+  /* CSKY_32_IS_BMASKI4 (insn).  */
+  adjust = (1 << (((insn & 0x3e00000) >> 21) + 1)) - 1;
+ }
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: base stacksize=0x%x\n", adjust);
+
+  /* May have zero or more insns which modify r4.  */
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: looking for r4 adjusters...\n");
+ }
+
+      offset = 4;
+      insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+      while (CSKY_IS_R4_ADJUSTER (insn2))
+ {
+  if (CSKY_32_IS_ADDI4 (insn2))
+    {
+      int imm = (insn2 & 0xfff) + 1;
+      adjust += imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: addi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_SUBI4 (insn2))
+    {
+      int imm = (insn2 & 0xfff) + 1;
+      adjust -= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: subi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_NOR4 (insn2))
+    {
+      adjust = ~adjust;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: nor r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_32_IS_ROTLI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      int temp = adjust >> (32 - imm);
+      adjust <<= imm;
+      adjust |= temp;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: rotli r4,r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_LISI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust <<= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: lsli r4,r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_BSETI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust |= (1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bseti r4,r4 %d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_BCLRI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust &= ~(1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bclri r4,r4 %d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_IXH4 (insn2))
+    {
+      adjust *= 3;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: ixh r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_32_IS_IXW4 (insn2))
+    {
+      adjust *= 5;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: ixw r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_16_IS_ADDI4 (insn2))
+    {
+      int imm = (insn2 & 0xff) + 1;
+      adjust += imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: addi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_SUBI4 (insn2))
+    {
+      int imm = (insn2 & 0xff) + 1;
+      adjust -= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: subi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_NOR4 (insn2))
+    {
+      adjust = ~adjust;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: nor r4,r4\n");
+ }
+    }
+  else if (CSKY_16_IS_BSETI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust |= (1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bseti r4, %d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_BCLRI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust &= ~(1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bclri r4, %d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_LSLI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust <<= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: lsli r4,r4, %d\n", imm);
+ }
+    }
+
+  offset += insn_len;
+  insn_len =  csky_get_insn (gdbarch, addr + offset, &insn2);
+ };
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog, "csky: done looking for"
+      " r4 adjusters\n");
+ }
+
+      /* If the next insn adjusts the stack pointer, we keep
+ everything; if not, we scrap it and we've found the
+ end of the prologue.  */
+      if (CSKY_IS_SUBU4 (insn2))
+ {
+  addr += offset;
+  stacksize += adjust;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: found stack adjustment of"
+  " 0x%x bytes.\n", adjust);
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: skipping to new address "
+  "0x%lx\n", addr);
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: continuing\n");
+    }
+  continue;
+ }
+
+      /* None of these instructions are prologue, so don't touch
+ anything.  */
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: no subu sp,sp,r4; NOT altering"
+      " stacksize.\n");
+ }
+      break;
+    }
+ }
+      else
+ {
+  /* insn_len != 4.  */
+
+  /* subi.sp sp,disp.  */
+  if (CSKY_16_IS_SUBI0 (insn))
+    {
+      int offset = CSKY_16_SUBI_IMM (insn);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: got subi r0,%d; continuing\n",
+      offset);
+ }
+      stacksize += offset;
+      continue;
+    }
+  /* stw.16 rz,(sp,disp).  */
+  else if (CSKY_16_IS_STWx0 (insn))
+    {
+      /* Spill register: see note for IS_STM above.  */
+      int disp;
+
+      rn = CSKY_16_ST_VAL_REGNUM (insn);
+      disp = CSKY_16_ST_OFFSET (insn);
+      register_offsets[rn] = stacksize - disp;
+      if (csky_debug)
+ print_savedreg_msg (rn, register_offsets, true);
+      continue;
+    }
+  else if (CSKY_16_IS_MOV_FP_SP (insn))
+    {
+      /* SP is saved to FP reg, means prologue may modify SP.  */
+      is_fp_saved = 1;
+      adjust_fp = stacksize;
+      continue;
+    }
+  else if (CSKY_16_IS_PUSH (insn))
+    {
+      /* Push for 16_bit.  */
+      int offset = 0;
+      if (CSKY_16_IS_PUSH_R15 (insn))
+ {
+  stacksize += 4;
+  register_offsets[15] = stacksize;
+  if (csky_debug)
+    print_savedreg_msg (15, register_offsets, false);
+  offset += 4;
+ }
+      if (CSKY_16_PUSH_LIST1 (insn))
+ {
+  int num = CSKY_16_PUSH_LIST1 (insn);
+  int tmp = 0;
+  stacksize += num * 4;
+  offset += num * 4;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+  "csky: push regs_array: r4-r%d\n",
+  4 + num - 1);
+    }
+  for (rn = 4; rn <= 4 + num - 1; rn++)
+    {
+       register_offsets[rn] = stacksize - tmp;
+       if (csky_debug)
+ {
+   fprintf_unfiltered (gdb_stdlog,
+       "csky: r%d saved at 0x%x"
+       " (offset %d)\n", rn,
+       register_offsets[rn], offset);
+ }
+       tmp += 4;
+    }
+ }
+
+      framesize = stacksize;
+      if (csky_debug)
+ fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+      continue;
+    }
+  else if (CSKY_16_IS_LRW4 (insn) || CSKY_16_IS_MOVI4 (insn))
+    {
+      int adjust = 0;
+      int offset = 0;
+      unsigned int insn2;
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: looking at large frame\n");
+ }
+      if (CSKY_16_IS_LRW4 (insn))
+ {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int offset = ((insn & 0x300) >> 3) | (insn & 0x1f);
+  int literal_addr = (addr + ( offset << 2)) & 0xfffffffc;
+  adjust = read_memory_unsigned_integer (literal_addr, 4,
+ byte_order);
+ }
+      else
+ {
+  /* CSKY_16_IS_MOVI4 (insn).  */
+  adjust = (insn  & 0xff);
+ }
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: base stacksize=0x%x\n", adjust);
+ }
+
+      /* May have zero or more instructions which modify r4.  */
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: looking for r4 adjusters...\n");
+ }
+      offset = 2;
+      insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+      while (CSKY_IS_R4_ADJUSTER (insn2))
+ {
+  if (CSKY_32_IS_ADDI4 (insn2))
+    {
+      int imm = (insn2 & 0xfff) + 1;
+      adjust += imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: addi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_SUBI4 (insn2))
+    {
+      int imm = (insn2 & 0xfff) + 1;
+      adjust -= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: subi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_NOR4 (insn2))
+    {
+      adjust = ~adjust;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: nor r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_32_IS_ROTLI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      int temp = adjust >> (32 - imm);
+      adjust <<= imm;
+      adjust |= temp;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: rotli r4,r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_LISI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust <<= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: lsli r4,r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_BSETI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust |= (1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bseti r4,r4 %d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_BCLRI4 (insn2))
+    {
+      int imm = ((insn2 >> 21) & 0x1f);
+      adjust &= ~(1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bclri r4,r4 %d\n", imm);
+ }
+    }
+  else if (CSKY_32_IS_IXH4 (insn2))
+    {
+      adjust *= 3;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: ixh r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_32_IS_IXW4 (insn2))
+    {
+      adjust *= 5;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: ixw r4,r4,r4\n");
+ }
+    }
+  else if (CSKY_16_IS_ADDI4 (insn2))
+    {
+      int imm = (insn2 & 0xff) + 1;
+      adjust += imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: addi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_SUBI4 (insn2))
+    {
+      int imm = (insn2 & 0xff) + 1;
+      adjust -= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: subi r4,%d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_NOR4 (insn2))
+    {
+      adjust = ~adjust;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: nor r4,r4\n");
+ }
+    }
+  else if (CSKY_16_IS_BSETI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust |= (1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bseti r4, %d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_BCLRI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust &= ~(1 << imm);
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: bclri r4, %d\n", imm);
+ }
+    }
+  else if (CSKY_16_IS_LSLI4 (insn2))
+    {
+      int imm = (insn2 & 0x1f);
+      adjust <<= imm;
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog,
+      "csky: lsli r4,r4, %d\n", imm);
+ }
+    }
+
+  offset += insn_len;
+  insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+ };
+
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog, "csky: "
+      "done looking for r4 adjusters\n");
+ }
+
+      /* If the next instruction adjusts the stack pointer, we keep
+ everything; if not, we scrap it and we've found the end
+ of the prologue.  */
+      if (CSKY_IS_SUBU4 (insn2))
+ {
+  addr += offset;
+  stacksize += adjust;
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "csky: "
+  "found stack adjustment of 0x%x"
+  " bytes.\n", adjust);
+      fprintf_unfiltered (gdb_stdlog, "csky: "
+  "skipping to new address 0x%lx\n",
+  addr);
+      fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+    }
+  continue;
+ }
+
+      /* None of these instructions are prologue, so don't touch
+ anything.  */
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog, "csky: no subu sp,r4; "
+      "NOT altering stacksize.\n");
+ }
+      break;
+    }
+ }
+
+      /* This is not a prologue instruction, so stop here.  */
+      if (csky_debug)
+ {
+  fprintf_unfiltered (gdb_stdlog, "csky: insn is not a prologue"
+      " insn -- ending scan\n");
+ }
+      break;
+    }
+
+  if (this_cache)
+    {
+      CORE_ADDR unwound_fp;
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      this_cache->framesize = framesize;
+
+      if (is_fp_saved)
+ {
+  this_cache->framereg = CSKY_FP_REGNUM;
+  unwound_fp = get_frame_register_unsigned (this_frame,
+    this_cache->framereg);
+  this_cache->prev_sp = unwound_fp + adjust_fp;
+ }
+      else
+ {
+  this_cache->framereg = CSKY_SP_REGNUM;
+  unwound_fp = get_frame_register_unsigned (this_frame,
+    this_cache->framereg);
+  this_cache->prev_sp = unwound_fp + stacksize;
+ }
+
+      /* Note where saved registers are stored.  The offsets in
+ REGISTER_OFFSETS are computed relative to the top of the frame.  */
+      for (rn = 0; rn < CSKY_NUM_GREGS; rn++)
+ {
+  if (register_offsets[rn] >= 0)
+    {
+      this_cache->saved_regs[rn].addr
+ = this_cache->prev_sp - register_offsets[rn];
+      if (csky_debug)
+ {
+  CORE_ADDR rn_value = read_memory_unsigned_integer (
+    this_cache->saved_regs[rn].addr, 4, byte_order);
+  fprintf_unfiltered (gdb_stdlog, "Saved register %s "
+      "stored at 0x%08lx, value=0x%08lx\n",
+      csky_register_names[rn],
+      (unsigned long)
+ this_cache->saved_regs[rn].addr,
+      (unsigned long) rn_value);
+ }
+    }
+ }
+      if (lr_type == LR_TYPE_EPC)
+ {
+  /* rte || epc .  */
+  this_cache->saved_regs[CSKY_PC_REGNUM]
+    = this_cache->saved_regs[CSKY_EPC_REGNUM];
+ }
+      else if (lr_type == LR_TYPE_FPC)
+ {
+  /* rfi || fpc .  */
+  this_cache->saved_regs[CSKY_PC_REGNUM]
+    = this_cache->saved_regs[CSKY_FPC_REGNUM];
+ }
+      else
+ {
+  this_cache->saved_regs[CSKY_PC_REGNUM]
+    = this_cache->saved_regs[CSKY_LR_REGNUM];
+ }
+    }
+
+  return addr;
+}
+
+/* Detect whether PC is at a point where the stack frame has been
+   destroyed.  */
+
+static int
+csky_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  unsigned int insn;
+  CORE_ADDR addr;
+  CORE_ADDR func_start, func_end;
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  bool fp_saved = false;
+  int insn_len;
+  for (addr = func_start; addr < func_end; addr += insn_len)
+    {
+      /* Get next insn.  */
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+
+      if (insn_len == 2)
+ {
+  /* Is sp is saved to fp.  */
+  if (CSKY_16_IS_MOV_FP_SP (insn))
+    fp_saved = true;
+  /* If sp was saved to fp and now being restored from
+     fp then it indicates the start of epilog.  */
+  else if (fp_saved && CSKY_16_IS_MOV_SP_FP (insn))
+    return pc >= addr;
+ }
+    }
+  return 0;
+}
+
+/* Implement the skip_prologue gdbarch hook.  */
+
+static CORE_ADDR
+csky_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal;
+  LONGEST return_value;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  const int default_search_limit = 128;
+
+  /* See if we can find the end of the prologue using the symbol table.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    {
+      CORE_ADDR post_prologue_pc
+ = skip_prologue_using_sal (gdbarch, func_addr);
+
+      if (post_prologue_pc != 0)
+ return std::max (pc, post_prologue_pc);
+    }
+  else
+    func_end = pc + default_search_limit;
+
+  /* Find the end of prologue.  Default lr_type.  */
+  return csky_analyze_prologue (gdbarch, pc, func_end, func_end,
+ NULL, NULL, LR_TYPE_R15);
+}
+
+/* Implement the breakpoint_kind_from_pc gdbarch method.  */
+
+static int
+csky_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+  if (csky_pc_is_csky16 (gdbarch, *pcptr))
+    return CSKY_INSN_SIZE16;
+  else
+    return CSKY_INSN_SIZE32;
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method.  */
+
+static const gdb_byte *
+csky_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+  *size = kind;
+  if (kind == CSKY_INSN_SIZE16)
+    {
+      static gdb_byte csky_16_breakpoint[] = { 0, 0 };
+      return csky_16_breakpoint;
+    }
+  else
+    {
+      static gdb_byte csky_32_breakpoint[] = { 0, 0, 0, 0 };
+      return csky_32_breakpoint;
+    }
+}
+
+/* Implement the memory_insert_breakpoint gdbarch method.  */
+
+static int
+csky_memory_insert_breakpoint (struct gdbarch *gdbarch,
+       struct bp_target_info *bp_tgt)
+{
+  int val;
+  const unsigned char *bp;
+  gdb_byte bp_write_record1[] = { 0, 0, 0, 0 };
+  gdb_byte bp_write_record2[] = { 0, 0, 0, 0 };
+  gdb_byte bp_record[] = { 0, 0, 0, 0 };
+
+  /* Sanity-check bp_address.  */
+  if (bp_tgt->reqstd_address % 2)
+    warning (_("Invalid breakpoint address 0x%x is an odd number.\n"),
+     (unsigned int) bp_tgt->reqstd_address);
+  scoped_restore restore_memory
+    = make_scoped_restore_show_memory_breakpoints (1);
+
+  /* Determine appropriate breakpoint_kind for this address.  */
+  bp_tgt->kind = csky_breakpoint_kind_from_pc (gdbarch,
+       &bp_tgt->reqstd_address);
+
+  /* Save the memory contents.  */
+  bp_tgt->shadow_len = bp_tgt->kind;
+
+  /* Fill bp_tgt->placed_address.  */
+  bp_tgt->placed_address = bp_tgt->reqstd_address;
+
+  if (bp_tgt->kind == CSKY_INSN_SIZE16)
+    {
+      if ((bp_tgt->reqstd_address % 4) == 0)
+ {
+  /* Read two bytes.  */
+  val = target_read_memory (bp_tgt->reqstd_address,
+    bp_tgt->shadow_contents, 2);
+  if (val)
+    return val;
+
+  /* Read two bytes.  */
+  val = target_read_memory (bp_tgt->reqstd_address + 2,
+    bp_record, 2);
+  if (val)
+    return val;
+
+  /* Write the breakpoint.  */
+  bp_write_record1[2] = bp_record[0];
+  bp_write_record1[3] = bp_record[1];
+  bp = bp_write_record1;
+  val = target_write_raw_memory (bp_tgt->reqstd_address, bp,
+ CSKY_WR_BKPT_MODE);
+ }
+      else
+ {
+  val = target_read_memory (bp_tgt->reqstd_address,
+    bp_tgt->shadow_contents, 2);
+  if (val)
+    return val;
+
+  val = target_read_memory (bp_tgt->reqstd_address - 2,
+    bp_record, 2);
+  if (val)
+    return val;
+
+  /* Write the breakpoint.  */
+  bp_write_record1[0] = bp_record[0];
+  bp_write_record1[1] = bp_record[1];
+  bp = bp_write_record1;
+  val = target_write_raw_memory (bp_tgt->reqstd_address - 2,
+ bp, CSKY_WR_BKPT_MODE);
+ }
+    }
+  else
+    {
+      if (bp_tgt->placed_address % 4 == 0)
+ {
+  val = target_read_memory (bp_tgt->reqstd_address,
+    bp_tgt->shadow_contents,
+    CSKY_WR_BKPT_MODE);
+  if (val)
+    return val;
+
+  /* Write the breakpoint.  */
+  bp = bp_write_record1;
+  val = target_write_raw_memory (bp_tgt->reqstd_address,
+ bp, CSKY_WR_BKPT_MODE);
+ }
+      else
+ {
+  val = target_read_memory (bp_tgt->reqstd_address,
+    bp_tgt->shadow_contents,
+    CSKY_WR_BKPT_MODE);
+  if (val)
+    return val;
+
+  val = target_read_memory (bp_tgt->reqstd_address - 2,
+    bp_record, 2);
+  if (val)
+    return val;
+
+  val = target_read_memory (bp_tgt->reqstd_address + 4,
+    bp_record + 2, 2);
+  if (val)
+    return val;
+
+  bp_write_record1[0] = bp_record[0];
+  bp_write_record1[1] = bp_record[1];
+  bp_write_record2[2] = bp_record[2];
+  bp_write_record2[3] = bp_record[3];
+
+  /* Write the breakpoint.  */
+  bp = bp_write_record1;
+  val = target_write_raw_memory (bp_tgt->reqstd_address - 2, bp,
+ CSKY_WR_BKPT_MODE);
+  if (val)
+    return val;
+
+  /* Write the breakpoint.  */
+  bp = bp_write_record2;
+  val = target_write_raw_memory (bp_tgt->reqstd_address + 2, bp,
+ CSKY_WR_BKPT_MODE);
+ }
+    }
+  return val;
+}
+
+/* Restore the breakpoint shadow_contents to the target.  */
+
+static int
+csky_memory_remove_breakpoint (struct gdbarch *gdbarch,
+       struct bp_target_info *bp_tgt)
+{
+  int val;
+  gdb_byte bp_record[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+  /* Different for shadow_len 2 or 4.  */
+  if (bp_tgt->shadow_len == 2)
+    {
+      /* Do word-sized writes on word-aligned boundaries and read
+ padding bytes as necessary.  */
+      if (bp_tgt->reqstd_address % 4 == 0)
+ {
+  val = target_read_memory (bp_tgt->reqstd_address + 2,
+    bp_record + 2, 2);
+  if (val)
+    return val;
+  bp_record[0] = bp_tgt->shadow_contents[0];
+  bp_record[1] = bp_tgt->shadow_contents[1];
+  return target_write_raw_memory (bp_tgt->reqstd_address,
+  bp_record, CSKY_WR_BKPT_MODE);
+ }
+      else
+ {
+  val = target_read_memory (bp_tgt->reqstd_address - 2,
+    bp_record, 2);
+  if (val)
+    return val;
+  bp_record[2] = bp_tgt->shadow_contents[0];
+  bp_record[3] = bp_tgt->shadow_contents[1];
+  return target_write_raw_memory (bp_tgt->reqstd_address - 2,
+  bp_record, CSKY_WR_BKPT_MODE);
+ }
+    }
+  else
+    {
+      /* Do word-sized writes on word-aligned boundaries and read
+ padding bytes as necessary.  */
+      if (bp_tgt->placed_address % 4 == 0)
+ {
+  return target_write_raw_memory (bp_tgt->reqstd_address,
+  bp_tgt->shadow_contents,
+  CSKY_WR_BKPT_MODE);
+ }
+      else
+ {
+  val = target_read_memory (bp_tgt->reqstd_address - 2,
+    bp_record, 2);
+  if (val)
+    return val;
+  val = target_read_memory (bp_tgt->reqstd_address + 4,
+    bp_record+6, 2);
+  if (val)
+    return val;
+
+  bp_record[2] = bp_tgt->shadow_contents[0];
+  bp_record[3] = bp_tgt->shadow_contents[1];
+  bp_record[4] = bp_tgt->shadow_contents[2];
+  bp_record[5] = bp_tgt->shadow_contents[3];
+
+  return target_write_raw_memory (bp_tgt->reqstd_address - 2,
+  bp_record,
+  CSKY_WR_BKPT_MODE * 2);
+ }
+    }
+}
+
+/* Determine link register type.  */
+
+static lr_type_t
+csky_analyze_lr_type (struct gdbarch *gdbarch,
+      CORE_ADDR start_pc, CORE_ADDR end_pc)
+{
+  CORE_ADDR addr;
+  unsigned int insn, rn, insn_len;
+  insn_len = 2;
+
+  for (addr = start_pc; addr < end_pc; addr += insn_len)
+    {
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+      if (insn_len == 4)
+ {
+  if (CSKY_32_IS_MFCR_EPSR (insn) || CSKY_32_IS_MFCR_EPC (insn)
+      || CSKY_32_IS_RTE (insn))
+    return LR_TYPE_EPC;
+ }
+      else if (CSKY_32_IS_MFCR_FPSR (insn) || CSKY_32_IS_MFCR_FPC (insn)
+       || CSKY_32_IS_RFI (insn))
+ return LR_TYPE_FPC;
+      else if (CSKY_32_IS_JMP (insn) || CSKY_32_IS_BR (insn)
+       || CSKY_32_IS_JMPIX (insn) || CSKY_32_IS_JMPI (insn))
+ return LR_TYPE_R15;
+      else
+ {
+  /* 16 bit instruction.  */
+  if (CSKY_16_IS_JMP (insn) || CSKY_16_IS_BR (insn)
+      || CSKY_16_IS_JMPIX (insn))
+    return LR_TYPE_R15;
+ }
+    }
+    return LR_TYPE_R15;
+}
+
+/* Heuristic unwinder.  */
+
+static struct csky_unwind_cache *
+csky_frame_unwind_cache (struct frame_info *this_frame)
+{
+  CORE_ADDR prologue_start, prologue_end, func_end, prev_pc, block_addr;
+  struct csky_unwind_cache *cache;
+  const struct block *bl;
+  unsigned long func_size = 0;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  unsigned int sp_regnum = CSKY_SP_REGNUM;
+
+  /* Default lr type is r15.  */
+  lr_type_t lr_type = LR_TYPE_R15;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct csky_unwind_cache);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  /* Assume there is no frame until proven otherwise.  */
+  cache->framereg = sp_regnum;
+
+  cache->framesize = 0;
+
+  prev_pc = get_frame_pc (this_frame);
+  block_addr = get_frame_address_in_block (this_frame);
+  if (find_pc_partial_function (block_addr, NULL, &prologue_start,
+ &func_end) == 0)
+    /* We couldn't find a function containing block_addr, so bail out
+       and hope for the best.  */
+    return cache;
+
+  /* Get the (function) symbol matching prologue_start.  */
+  bl = block_for_pc (prologue_start);
+  if (bl != NULL)
+    func_size = bl->endaddr - bl->startaddr;
+  else
+    {
+      struct bound_minimal_symbol msymbol
+ = lookup_minimal_symbol_by_pc (prologue_start);
+      if (msymbol.minsym != NULL)
+ func_size = MSYMBOL_SIZE (msymbol.minsym);
+    }
+
+  /* If FUNC_SIZE is 0 we may have a special-case use of lr
+     e.g. exception or interrupt.  */
+  if (func_size == 0)
+    lr_type = csky_analyze_lr_type (gdbarch, prologue_start, func_end);
+
+  prologue_end = std::min (func_end, prev_pc);
+
+  /* Analyze the function prologue.  */
+  csky_analyze_prologue (gdbarch, prologue_start, prologue_end,
+    func_end, this_frame, cache, lr_type);
+
+  /* gdbarch_sp_regnum contains the value and not the address.  */
+  trad_frame_set_value (cache->saved_regs, sp_regnum, cache->prev_sp);
+  return cache;
+}
+
+/* Implement the unwind_pc gdbarch method.  */
+
+static CORE_ADDR
+csky_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, CSKY_PC_REGNUM);
+}
+
+/* Implement the this_id function for the normal unwinder.  */
+
+static void
+csky_frame_this_id (struct frame_info *this_frame,
+    void **this_prologue_cache, struct frame_id *this_id)
+{
+  struct csky_unwind_cache *cache;
+  struct frame_id id;
+
+  if (*this_prologue_cache == NULL)
+    *this_prologue_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_prologue_cache;
+
+  /* This marks the outermost frame.  */
+  if (cache->prev_sp == 0)
+    return;
+
+  id = frame_id_build (cache->prev_sp, get_frame_func (this_frame));
+  *this_id = id;
+}
+
+/* Implement the prev_register function for the normal unwinder.  */
+
+static struct value *
+csky_frame_prev_register (struct frame_info *this_frame,
+  void **this_prologue_cache, int regnum)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_prologue_cache == NULL)
+    *this_prologue_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_prologue_cache;
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+       regnum);
+}
+
+/* Data structures for the normal prologue-analysis-based
+   unwinder.  */
+
+static const struct frame_unwind csky_unwind_cache = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  csky_frame_this_id,
+  csky_frame_prev_register,
+  NULL,
+  default_frame_sniffer,
+  NULL,
+  NULL
+};
+
+
+
+static int
+csky_stub_unwind_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+  CORE_ADDR addr_in_block;
+
+  addr_in_block = get_frame_address_in_block (this_frame);
+
+  if (find_pc_partial_function (addr_in_block, NULL, NULL, NULL) == 0
+      || in_plt_section (addr_in_block))
+    return 1;
+
+  return 0;
+}
+
+static struct csky_unwind_cache *
+csky_make_stub_cache (struct frame_info *this_frame)
+{
+  struct csky_unwind_cache *cache;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct csky_unwind_cache);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  cache->prev_sp = get_frame_register_unsigned (this_frame,
CSKY_SP_REGNUM);
+
+  return cache;
+}
+
+static void
+csky_stub_this_id (struct frame_info *this_frame,
+  void **this_cache,
+  struct frame_id *this_id)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_make_stub_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  /* Our frame ID for a stub frame is the current SP and LR.  */
+  *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
+}
+
+static struct value *
+csky_stub_prev_register (struct frame_info *this_frame,
+    void **this_cache,
+    int prev_regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_make_stub_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  /* If we are asked to unwind the PC, then return the LR.  */
+  if (prev_regnum == CSKY_PC_REGNUM)
+    {
+      CORE_ADDR lr;
+
+      lr = frame_unwind_register_unsigned (this_frame, CSKY_LR_REGNUM);
+      return frame_unwind_got_constant (this_frame, prev_regnum, lr);
+    }
+
+  if (prev_regnum == CSKY_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, prev_regnum,
cache->prev_sp);
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+       prev_regnum);
+}
+
+struct frame_unwind csky_stub_unwind = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  csky_stub_this_id,
+  csky_stub_prev_register,
+  NULL,
+  csky_stub_unwind_sniffer
+};
+
+/* Implement the this_base, this_locals, and this_args hooks
+   for the normal unwinder.  */
+
+static CORE_ADDR
+csky_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  return cache->prev_sp - cache->framesize;
+}
+
+static const struct frame_base csky_frame_base = {
+  &csky_unwind_cache,
+  csky_frame_base_address,
+  csky_frame_base_address,
+  csky_frame_base_address
+};
+
+/* Implement the dummy_id gdbarch method.  The frame ID's base
+   needs to match the TOS value saved by save_dummy_frame_tos,
+   and the PC should match the dummy frame's breakpoint.  */
+
+static struct frame_id
+csky_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  unsigned int sp_regnum = CSKY_SP_REGNUM;
+
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, sp_regnum);
+  return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+/* Initialize register access method.  */
+
+static void
+csky_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+    struct dwarf2_frame_state_reg *reg,
+    struct frame_info *this_frame)
+{
+  if (regnum == gdbarch_pc_regnum (gdbarch))
+    reg->how = DWARF2_FRAME_REG_RA;
+  else if (regnum == gdbarch_sp_regnum (gdbarch))
+    reg->how = DWARF2_FRAME_REG_CFA;
+}
+
+/* Create csky register groups.  */
+
+static void
+csky_init_reggroup ()
+{
+  cr_reggroup = reggroup_new ("cr", USER_REGGROUP);
+  fr_reggroup = reggroup_new ("fr", USER_REGGROUP);
+  vr_reggroup = reggroup_new ("vr", USER_REGGROUP);
+  mmu_reggroup = reggroup_new ("mmu", USER_REGGROUP);
+  prof_reggroup = reggroup_new ("profiling", USER_REGGROUP);
+}
+
+/* Add register groups into reggroup list.  */
+
+static void
+csky_add_reggroups (struct gdbarch *gdbarch)
+{
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, cr_reggroup);
+  reggroup_add (gdbarch, fr_reggroup);
+  reggroup_add (gdbarch, vr_reggroup);
+  reggroup_add (gdbarch, mmu_reggroup);
+  reggroup_add (gdbarch, prof_reggroup);
+}
+
+/* Return the groups that a CSKY register can be categorised into.  */
+
+static int
+csky_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+  struct reggroup *reggroup)
+{
+  int raw_p;
+
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
+    return 0;
+
+  if (reggroup == all_reggroup)
+    return 1;
+
+  raw_p = regnum < gdbarch_num_regs (gdbarch);
+  if (reggroup == save_reggroup || reggroup == restore_reggroup)
+    return raw_p;
+
+  if (((regnum >= CSKY_R0_REGNUM) && (regnum <= CSKY_R0_REGNUM + 31))
+      && (reggroup == general_reggroup))
+    return 1;
+
+  if (((regnum == CSKY_PC_REGNUM)
+       || ((regnum >= CSKY_CR0_REGNUM)
+   && (regnum <= CSKY_CR0_REGNUM + 30)))
+      && (reggroup == cr_reggroup))
+    return 2;
+
+  if ((((regnum >= CSKY_VR0_REGNUM) && (regnum <= CSKY_VR0_REGNUM + 15))
+       || ((regnum >= CSKY_VCR0_REGNUM)
+   && (regnum <= CSKY_VCR0_REGNUM + 2)))
+      && (reggroup == vr_reggroup))
+    return 3;
+
+  if (((regnum >= CSKY_MMU_REGNUM) && (regnum <= CSKY_MMU_REGNUM + 8))
+      && (reggroup == mmu_reggroup))
+    return 4;
+
+  if (((regnum >= CSKY_PROFCR_REGNUM)
+       && (regnum <= CSKY_PROFCR_REGNUM + 48))
+      && (reggroup == prof_reggroup))
+    return 5;
+
+  if ((((regnum >= CSKY_FR0_REGNUM) && (regnum <= CSKY_FR0_REGNUM + 15))
+       || ((regnum >= CSKY_VCR0_REGNUM) && (regnum <= CSKY_VCR0_REGNUM
+ 2)))
+      && (reggroup == fr_reggroup))
+    return 6;
+
+  return 0;
+}
+
+/* Implement the dwarf2_reg_to_regnum gdbarch method.  */
+
+static int
+csky_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int dw_reg)
+{
+  if (dw_reg < 0 || dw_reg >= CSKY_NUM_REGS)
+    return -1;
+  return dw_reg;
+}
+
+/* Override interface for command: info register.  */
+
+static void
+csky_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
+   struct frame_info *frame, int regnum, int all)
+{
+  /* Call default print_registers_info function.  */
+  default_print_registers_info (gdbarch, file, frame, regnum, all);
+
+  /* For command: info register.  */
+  if (regnum == -1 && all == 0)
+    {
+      default_print_registers_info (gdbarch, file, frame,
+    CSKY_PC_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+    CSKY_EPC_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+    CSKY_CR0_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+    CSKY_EPSR_REGNUM, 0);
+    }
+  return;
+}
+
+/* Initialize the current architecture based on INFO.  If possible,
+   re-use an architecture from ARCHES, which is a list of
+   architectures already created during this debugging session.
+
+   Called at program startup, when reading a core file, and when
+   reading a binary file.  */
+
+static struct gdbarch *
+csky_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+
+  /* Find a candidate among the list of pre-declared architectures.  */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return arches->gdbarch;
+
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = XCNEW (struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* Target data types.  */
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_addr_bit (gdbarch, 32);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+
+  /* Information about the target architecture.  */
+  set_gdbarch_return_value (gdbarch, csky_return_value);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch,
csky_breakpoint_kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch,
csky_sw_breakpoint_from_kind);
+
+  /* Register architecture.  */
+  set_gdbarch_num_regs (gdbarch, CSKY_NUM_REGS);
+  set_gdbarch_pc_regnum (gdbarch, CSKY_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CSKY_SP_REGNUM);
+  set_gdbarch_register_name (gdbarch, csky_register_name);
+  set_gdbarch_register_type (gdbarch, csky_register_type);
+  set_gdbarch_read_pc (gdbarch, csky_read_pc);
+  set_gdbarch_write_pc (gdbarch, csky_write_pc);
+  set_gdbarch_print_registers_info (gdbarch, csky_print_registers_info);
+  csky_add_reggroups (gdbarch);
+  set_gdbarch_register_reggroup_p (gdbarch, csky_register_reggroup_p);
+  set_gdbarch_stab_reg_to_regnum (gdbarch, csky_dwarf_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, csky_dwarf_reg_to_regnum);
+  dwarf2_frame_set_init_reg (gdbarch, csky_dwarf2_frame_init_reg);
+
+  /* Functions to analyze frames.  */
+  frame_base_set_default (gdbarch, &csky_frame_base);
+  set_gdbarch_skip_prologue (gdbarch, csky_skip_prologue);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_frame_align (gdbarch, csky_frame_align);
+  set_gdbarch_stack_frame_destroyed_p (gdbarch,
csky_stack_frame_destroyed_p);
+
+  /* Functions to access frame data.  */
+  set_gdbarch_unwind_pc (gdbarch, csky_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, csky_unwind_sp);
+
+  /* Functions handling dummy frames.  */
+  set_gdbarch_push_dummy_call (gdbarch, csky_push_dummy_call);
+  set_gdbarch_dummy_id (gdbarch, csky_dummy_id);
+
+  /* Frame unwinders.  Use DWARF debug info if available,
+     otherwise use our own unwinder.  */
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &csky_stub_unwind);
+  frame_unwind_append_unwinder (gdbarch, &csky_unwind_cache);
+
+  /* Breakpoints.  */
+  set_gdbarch_memory_insert_breakpoint (gdbarch,
+ csky_memory_insert_breakpoint);
+  set_gdbarch_memory_remove_breakpoint (gdbarch,
+ csky_memory_remove_breakpoint);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Support simple overlay manager.  */
+  set_gdbarch_overlay_update (gdbarch, simple_overlay_update);
+  set_gdbarch_char_signed (gdbarch, 0);
+  return gdbarch;
+}
+
+void
+_initialize_csky_tdep (void)
+{
+
+  register_gdbarch_init (bfd_arch_csky, csky_gdbarch_init);
+
+  csky_init_reggroup ();
+
+  /* Allow debugging this file's internals.  */
+  add_setshow_boolean_cmd ("csky", class_maintenance, &csky_debug,
+   _("Set C-Sky debugging."),
+   _("Show C-Sky debugging."),
+   _("When on, C-Sky specific debugging is enabled."),
+   NULL,
+   NULL,
+   &setdebuglist, &showdebuglist);
+}
diff --git a/gdb/csky-tdep.h b/gdb/csky-tdep.h
new file mode 100644
index 0000000000..49c29a9e1c
--- /dev/null
+++ b/gdb/csky-tdep.h
@@ -0,0 +1,355 @@
+/* Target-dependent code for the CSKY architecture, for GDB.
+
+   Copyright (C) 2010-2018 Free Software Foundation, 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/>.  */
+
+#ifndef CSKY_TDEP_H
+#define CSKY_TDEP_H
+
+/* How to interpret the contents of the link register.  */
+enum lr_type_t
+{
+  LR_TYPE_R15,
+  LR_TYPE_EPC,
+  LR_TYPE_FPC
+};
+
+/* Target-dependent structure in gdbarch.  */
+struct gdbarch_tdep
+{
+  /* This is Unused.  */
+};
+
+/* Instruction sizes.  */
+enum csky_insn_size_t
+{
+  CSKY_INSN_SIZE16 = 2,
+  CSKY_INSN_SIZE32 = 4
+};
+
+/* CSKY register numbers.  */
+enum csky_regnum
+{
+  CSKY_R0_REGNUM = 0, /* General registers.  */
+  CSKY_R15_REGNUM = 15,
+  CSKY_PC_REGNUM = 72,
+  CSKY_HI_REGNUM = 20,
+  CSKY_LO_REGNUM = 21,
+  CSKY_CR0_REGNUM = 89,
+  CSKY_VBR_REGNUM = CSKY_CR0_REGNUM + 1,
+  CSKY_EPSR_REGNUM = CSKY_CR0_REGNUM + 2,
+  CSKY_FPSR_REGNUM = CSKY_CR0_REGNUM + 3,
+  CSKY_EPC_REGNUM = CSKY_CR0_REGNUM + 4,
+  CSKY_FPC_REGNUM = CSKY_CR0_REGNUM + 5,
+
+  /* Float register 0.  */
+  CSKY_FR0_REGNUM = 40,
+  CSKY_VCR0_REGNUM = 121,
+  CSKY_MMU_REGNUM = 128,
+  CSKY_PROFCR_REGNUM = 140,
+  CSKY_PROFGR_REGNUM = 144,
+  CSKY_FP_REGNUM = 8,
+
+  /* Vector register 0.  */
+  CSKY_VR0_REGNUM = 56,
+
+  /* m32r calling convention.  */
+  CSKY_SP_REGNUM = CSKY_R0_REGNUM + 14,
+  CSKY_RET_REGNUM = CSKY_R0_REGNUM,
+
+  /* Argument registers.  */
+  CSKY_ABI_A0_REGNUM = 0,
+  CSKY_ABI_LAST_ARG_REGNUM = 3,
+
+  /* Link register, r15.  */
+  CSKY_LR_REGNUM = CSKY_R15_REGNUM,
+
+  /* Processor status register, cr0.  */
+  CSKY_PSR_REGNUM = CSKY_CR0_REGNUM,
+
+  CSKY_MAX_REGISTER_SIZE = 16,
+  CSKY_MAX_REGS = 253
+};
+
+/* ICE registers.  */
+#define CSKY_CRBANK_NUM_REGS 32
+
+/* Number of processor registers w/o ICE registers.  */
+#define CSKY_NUM_REGS (CSKY_MAX_REGS - CSKY_CRBANK_NUM_REGS)
+
+/* size.  */
+#define CSKY_16_ST_SIZE(insn) (1 << ((insn & 0x1800) >> 11))
+/* rx.  */
+#define CSKY_16_ST_ADDR_REGNUM(insn) ((insn & 0x700) >> 8)
+/* disp.  */
+#define CSKY_16_ST_OFFSET(insn) ((insn & 0x1f) << ((insn & 0x1800) >> 11))
+/* ry.  */
+#define CSKY_16_ST_VAL_REGNUM(insn) ((insn & 0xe0) >> 5)
+
+/* st16.w rz, (sp, disp).  */
+#define CSKY_16_IS_STWx0(insn) ((insn & 0xf800) == 0xb800)
+#define CSKY_16_STWx0_VAL_REGNUM(insn) CSKY_16_ST_ADDR_REGNUM (insn)
+
+/* disp.  */
+#define CSKY_16_STWx0_OFFSET(insn) \
+  ((((insn & 0x700) >> 3) + (insn & 0x1f)) << 2)
+
+/* Check ld16 but not ld16 sp.  */
+#define CSKY_16_IS_LD(insn) \
+  (((insn & 0xe000) == 0x8000) && (insn & 0x1800) != 0x1800)
+/* size.  */
+#define CSKY_16_LD_SIZE(insn) CSKY_16_ST_SIZE (insn)
+/* rx.  */
+#define CSKY_16_LD_ADDR_REGNUM(insn) CSKY_16_ST_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_16_LD_OFFSET(insn) CSKY_16_ST_OFFSET (insn)
+
+/* ld16.w rz,(sp,disp).  */
+#define CSKY_16_IS_LDWx0(insn) ((insn & 0xf800) == 0x9800)
+/*disp.  */
+#define CSKY_16_LDWx0_OFFSET(insn) CSKY_16_STWx0_OFFSET (insn)
+
+/* st32.b/h/w/d.  */
+#define CSKY_32_IS_ST(insn) ((insn & 0xfc00c000) == 0xdc000000)
+
+/* size: b/h/w/d.  */
+#define CSKY_32_ST_SIZE(insn) (1 << ((insn & 0x3000) >> 12))
+/* rx.  */
+#define CSKY_32_ST_ADDR_REGNUM(insn) ((insn & 0x001f0000) >> 16)
+/* disp.  */
+#define CSKY_32_ST_OFFSET(insn) ((insn & 0xfff) << ((insn & 0x3000) >> 12))
+/* ry.  */
+#define CSKY_32_ST_VAL_REGNUM(insn) ((insn & 0x03e00000) >> 21)
+
+/* stw ry, (sp, disp).  */
+#define CSKY_32_IS_STWx0(insn) ((insn & 0xfc1ff000) == 0xdc0e2000)
+
+/* stm32 ry-rz, (rx).  */
+#define CSKY_32_IS_STM(insn) ((insn & 0xfc00ffe0) == 0xd4001c20)
+/* rx.  */
+#define CSKY_32_STM_ADDR_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* Count of registers.  */
+#define CSKY_32_STM_SIZE(insn) (insn & 0x1f)
+/* ry.  */
+#define CSKY_32_STM_VAL_REGNUM(insn) ((insn & 0x03e00000) >> 21)
+/* stm32 ry-rz, (sp).  */
+#define CSKY_32_IS_STMx0(insn) ((insn & 0xfc1fffe0) == 0xd40e1c20)
+
+/* str32.b/h/w rz, (rx, ry << offset).  */
+#define CSKY_32_IS_STR(insn) \
+  (((insn & 0xfc000000) == 0xd4000000) && !(CSKY_32_IS_STM (insn)))
+/* rx.  */
+#define CSKY_32_STR_X_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* ry.  */
+#define CSKY_32_STR_Y_REGNUM(insn) ((insn >> 21) & 0x1f)
+/* size: b/h/w.  */
+#define CSKY_32_STR_SIZE(insn) (1 << ((insn & 0x0c00) >> 10))
+/* imm (for rx + ry * imm).  */
+#define CSKY_32_STR_OFFSET(insn) ((insn & 0x000003e0) >> 5)
+
+/* stex32.w rz, (rx, disp).  */
+#define CSKY_32_IS_STEX(insn) ((insn & 0xfc00f000) == 0xdc007000)
+/* rx.  */
+#define CSKY_32_STEX_ADDR_REGNUM(insn) ((insn & 0x1f0000) >> 16)
+/* disp.  */
+#define CSKY_32_STEX_OFFSET(insn) ((insn & 0x0fff) << 2)
+
+/* ld.b/h/w.  */
+#define CSKY_32_IS_LD(insn) ((insn & 0xfc00c000) == 0xd8000000)
+/* size.  */
+#define CSKY_32_LD_SIZE(insn) CSKY_32_ST_SIZE (insn)
+/* rx.  */
+#define CSKY_32_LD_ADDR_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_32_LD_OFFSET(insn) CSKY_32_ST_OFFSET (insn)
+#define CSKY_32_IS_LDM(insn) ((insn & 0xfc00ffe0) == 0xd0001c20)
+/* rx.  */
+#define CSKY_32_LDM_ADDR_REGNUM(insn) CSKY_32_STM_ADDR_REGNUM (insn)
+/* Count of registers.  */
+#define CSKY_32_LDM_SIZE(insn) CSKY_32_STM_SIZE (insn)
+
+/* ldr32.b/h/w rz, (rx, ry << offset).  */
+#define CSKY_32_IS_LDR(insn) \
+  (((insn & 0xfc00fe00) == 0xd0000000) && !(CSKY_32_IS_LDM (insn)))
+/* rx.  */
+#define CSKY_32_LDR_X_REGNUM(insn) CSKY_32_STR_X_REGNUM (insn)
+/* ry.  */
+#define CSKY_32_LDR_Y_REGNUM(insn) CSKY_32_STR_Y_REGNUM (insn)
+/* size: b/h/w.  */
+#define CSKY_32_LDR_SIZE(insn) CSKY_32_STR_SIZE (insn)
+/* imm (for rx + ry*imm).  */
+#define CSKY_32_LDR_OFFSET(insn) CSKY_32_STR_OFFSET (insn)
+
+#define CSKY_32_IS_LDEX(insn) ((insn & 0xfc00f000) == 0xd8007000)
+/* rx.  */
+#define CSKY_32_LDEX_ADDR_REGNUM(insn) CSKY_32_STEX_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_32_LDEX_OFFSET(insn) CSKY_32_STEX_OFFSET (insn)
+
+/* subi.sp sp, disp.  */
+#define CSKY_16_IS_SUBI0(insn) ((insn & 0xfce0) == 0x1420)
+/* disp.  */
+#define CSKY_16_SUBI_IMM(insn) ((((insn & 0x300) >> 3) + (insn & 0x1f))
<< 2)
+
+/* subi32 sp,sp,oimm12.  */
+#define CSKY_32_IS_SUBI0(insn) ((insn & 0xfffff000) == 0xe5ce1000)
+/* oimm12.  */
+#define CSKY_32_SUBI_IMM(insn) ((insn & 0xfff) + 1)
+
+/* push16.  */
+#define CSKY_16_IS_PUSH(insn) ((insn & 0xffe0) == 0x14c0)
+#define CSKY_16_IS_PUSH_R15(insn) ((insn & 0x10) == 0x10)
+#define CSKY_16_PUSH_LIST1(insn) (insn & 0xf) /* r4 - r11.  */
+
+/* pop16.  */
+#define CSKY_16_IS_POP(insn) ((insn & 0xffe0) == 0x1480)
+#define CSKY_16_IS_POP_R15(insn) CSKY_16_IS_PUSH_R15 (insn)
+#define CSKY_16_POP_LIST1(insn) CSKY_16_PUSH_LIST1 (insn) /* r4 - r11.  */
+
+/* push32.  */
+#define CSKY_32_IS_PUSH(insn) ((insn & 0xfffffe00) == 0xebe00000)
+#define CSKY_32_IS_PUSH_R29(insn) ((insn & 0x100) == 0x100)
+#define CSKY_32_IS_PUSH_R15(insn) ((insn & 0x10) == 0x10)
+#define CSKY_32_PUSH_LIST1(insn) (insn & 0xf) /* r4 - r11.  */
+#define CSKY_32_PUSH_LIST2(insn) ((insn & 0xe0) >> 5) /* r16 - r17.  */
+
+/* pop32.  */
+#define CSKY_32_IS_POP(insn) ((insn & 0xfffffe00) == 0xebc00000)
+#define CSKY_32_IS_POP_R29(insn) CSKY_32_IS_PUSH_R29 (insn)
+#define CSKY_32_IS_POP_R15(insn) CSKY_32_IS_PUSH_R15 (insn)
+#define CSKY_32_POP_LIST1(insn) CSKY_32_PUSH_LIST1 (insn) /* r4 - r11.  */
+#define CSKY_32_POP_LIST2(insn) CSKY_32_PUSH_LIST2 (insn) /* r16 - r17.  */
+
+/* Adjust sp by r4(l0).  */
+/* lrw r4, literal.  */
+#define CSKY_16_IS_LRW4(x) (((x) &0xfce0) == 0x1080)
+/* movi r4, imm8.  */
+#define CSKY_16_IS_MOVI4(x) (((x) &0xff00) == 0x3400)
+
+/* addi r4, oimm8.  */
+#define CSKY_16_IS_ADDI4(x) (((x) &0xff00) == 0x2400)
+/* subi r4, oimm8.  */
+#define CSKY_16_IS_SUBI4(x) (((x) &0xff00) == 0x2c00)
+
+/* nor16 r4, r4.  */
+#define CSKY_16_IS_NOR4(x) ((x) == 0x6d12)
+
+/* lsli r4, r4, imm5.  */
+#define CSKY_16_IS_LSLI4(x) (((x) &0xffe0) == 0x4480)
+/* bseti r4, imm5.  */
+#define CSKY_16_IS_BSETI4(x) (((x) &0xffe0) == 0x3ca0)
+/* bclri r4, imm5.  */
+#define CSKY_16_IS_BCLRI4(x) (((x) &0xffe0) == 0x3c80)
+
+/* subu sp, r4.  */
+#define CSKY_16_IS_SUBU4(x) ((x) == 0x6392)
+
+#define CSKY_16_IS_R4_ADJUSTER(x) \
+  (CSKY_16_IS_ADDI4 (x) || CSKY_16_IS_SUBI4 (x) || CSKY_16_IS_BSETI4 (x) \
+   || CSKY_16_IS_BCLRI4 (x) || CSKY_16_IS_NOR4 (x) || CSKY_16_IS_LSLI4 (x))
+
+/* lrw r4, literal.  */
+#define CSKY_32_IS_LRW4(x) (((x) &0xffff0000) == 0xea840000)
+/* movi r4, imm16.  */
+#define CSKY_32_IS_MOVI4(x) (((x) &0xffff0000) == 0xea040000)
+/* movih r4, imm16.  */
+#define CSKY_32_IS_MOVIH4(x) (((x) &0xffff0000) == 0xea240000)
+/* bmaski r4, oimm5.  */
+#define CSKY_32_IS_BMASKI4(x) (((x) &0xfc1fffff) == 0xc4005024)
+/* addi r4, r4, oimm12.  */
+#define CSKY_32_IS_ADDI4(x) (((x) &0xfffff000) == 0xe4840000)
+/* subi r4, r4, oimm12.  */
+#define CSKY_32_IS_SUBI4(x) (((x) &0xfffff000) == 0xe4810000)
+
+/* nor32 r4, r4, r4.  */
+#define CSKY_32_IS_NOR4(x) ((x) == 0xc4842484)
+/* rotli r4, r4, imm5.  */
+#define CSKY_32_IS_ROTLI4(x) (((x) &0xfc1fffff) == 0xc4044904)
+/* lsli r4, r4, imm5.  */
+#define CSKY_32_IS_LISI4(x) (((x) &0xfc1fffff) == 0xc4044824)
+/* bseti32 r4, r4, imm5.  */
+#define CSKY_32_IS_BSETI4(x) (((x) &0xfc1fffff) == 0xc4042844)
+/* bclri32 r4, r4, imm5.  */
+#define CSKY_32_IS_BCLRI4(x) (((x) &0xfc1fffff) == 0xc4042824)
+/* ixh r4, r4, r4.  */
+#define CSKY_32_IS_IXH4(x) ((x) == 0xc4840824)
+/* ixw r4, r4, r4.  */
+#define CSKY_32_IS_IXW4(x) ((x) == 0xc4840844)
+/* subu32 sp, sp, r4.  */
+#define CSKY_32_IS_SUBU4(x) ((x) == 0xc48e008e)
+
+#define CSKY_32_IS_R4_ADJUSTER(x) \
+  (CSKY_32_IS_ADDI4 (x) || CSKY_32_IS_SUBI4 (x) || CSKY_32_IS_ROTLI4 (x) \
+   || CSKY_32_IS_IXH4 (x) || CSKY_32_IS_IXW4 (x) || CSKY_32_IS_NOR4 (x) \
+   || CSKY_32_IS_BSETI4 (x) || CSKY_32_IS_BCLRI4 (x) ||
CSKY_32_IS_LISI4 (x))
+
+#define CSKY_IS_R4_ADJUSTER(x) \
+  (CSKY_32_IS_R4_ADJUSTER (x) || CSKY_16_IS_R4_ADJUSTER (x))
+#define CSKY_IS_SUBU4(x) (CSKY_32_IS_SUBU4 (x) || CSKY_16_IS_SUBU4 (x))
+
+/* mfcr rz, epsr.  */
+#define CSKY_32_IS_MFCR_EPSR(insn) ((insn & 0xffffffe0) == 0xc0026020)
+/* mfcr rz, fpsr.  */
+#define CSKY_32_IS_MFCR_FPSR(insn) ((insn & 0xffffffe0) == 0xc0036020)
+/* mfcr rz, epc.  */
+#define CSKY_32_IS_MFCR_EPC(insn) ((insn & 0xffffffe0) == 0xc0046020)
+/* mfcr rz, fpc.  */
+#define CSKY_32_IS_MFCR_FPC(insn) ((insn & 0xffffffe0) == 0xc0056020)
+
+#define CSKY_32_IS_RTE(insn) (insn == 0xc0004020)
+#define CSKY_32_IS_RFI(insn) (insn == 0xc0004420)
+#define CSKY_32_IS_JMP(insn) ((insn & 0xffe0ffff) == 0xe8c00000)
+#define CSKY_16_IS_JMP(insn) ((insn & 0xffc3) == 0x7800)
+#define CSKY_32_IS_JMPI(insn) ((insn & 0xffff0000) == 0xeac00000)
+#define CSKY_32_IS_JMPIX(insn) ((insn & 0xffe0fffc) == 0xe9e00000)
+#define CSKY_16_IS_JMPIX(insn) ((insn & 0xf8fc) == 0x38e0)
+
+#define CSKY_16_IS_BR(insn) ((insn & 0xfc00) == 0x0400)
+#define CSKY_32_IS_BR(insn) ((insn & 0xffff0000) == 0xe8000000)
+#define CSKY_16_IS_MOV_FP_SP(insn) (insn == 0x6e3b)     /* mov r8, r14.  */
+#define CSKY_32_IS_MOV_FP_SP(insn) (insn == 0xc40e4828) /* mov r8, r14.  */
+#define CSKY_16_IS_MOV_SP_FP(insn) (insn == 0x6fa3)     /* mov r14, r8.  */
+#define CSKY_32_INSN_MASK 0xc000
+#define CSKY_BKPT_INSN 0x0
+#define CSKY_NUM_GREGS 32
+/* 32 general regs + 4.  */
+#define CSKY_NUM_GREGS_SAVED_GREGS (CSKY_NUM_GREGS + 4)
+
+/* CSKY software bkpt write-mode.  */
+#define CSKY_WR_BKPT_MODE 4
+
+/* Define insns for parse rt_sigframe.  */
+/* There are three words(sig, pinfo, puc) before siginfo.  */
+#define CSKY_SIGINFO_OFFSET 0xc
+
+/* Size of struct siginfo.  */
+#define CSKY_SIGINFO_SIZE 0x80
+
+/* There are five words(uc_flags, uc_link, and three for uc_stack)
+   in struct ucontext before sigcontext.  */
+#define CSKY_UCONTEXT_SIGCONTEXT 0x14
+
+/* There is a word(sc_mask) before sc_usp.  */
+#define CSKY_SIGCONTEXT_SC_USP 0x4
+
+/* There is a word(sc_usp) before sc_a0.  */
+#define CSKY_SIGCONTEXT_SC_A0 0x4
+
+#define CSKY_MOVI_R7_173 0x00adea07
+#define CSKY_TRAP_0 0x2020c000
+
+#endif
--
2.11.0


Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Hafiz Abid Qadeer
Polite Ping.

Thanks,
--
Hafiz Abid Qadeer
Mentor Embedded/CodeSourcery
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Hafiz Abid Qadeer
In reply to this post by Hafiz Abid Qadeer
Polite ping.
________________________________________
From: Hafiz Abid Qadeer <[hidden email]>
Sent: Saturday, July 28, 2018 12:12 AM
To: Tom Tromey
Cc: [hidden email]; [hidden email]; [hidden email]
Subject: Re: [1/2] C-SKY Port

Hi Tom,
Thanks for the review. Please see comments and updated patch below

On 27/07/18 16:49, Tom Tromey wrote:

>>>>>> ">" == Hafiz Abid Qadeer <[hidden email]> writes:
>
>>> Add support for new target 'csky'.
>
>>> 2018-07-25  Jiangshuai Li  <[hidden email]>
>>>         Hafiz Abid Qadeer  <[hidden email]>
>>>         Don Breazeal  <[hidden email]>
>
> I didn't check the copyright assignment situation, but for a patch of
> this size, assignments are needed.  I assume codesourcery has some kind
> of blanket assignment, but what about Jiangshuai Li?
Yes, csky aslo have a copyright assignment.

>
>>> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
>
>>> +csky*-linux*)
Done.

>
>>> +csky*-*)
Done.

>
> It's more normal to mention all the "-"s, so "csky*-*-linux*" and "csky*-*-*".
>
> I don't know anything about C-SKY, so I didn't really look deeply at the
> arch-specific bits.  I assume those pass your testing.
>
>>> diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
>
>>> +struct stack_item
>>> +{
>>> +  int len;
>>> +  struct stack_item *prev;
>>> +  void *data;
>
> Seems to me that this could be gdb_byte instead of void here, and in
> push_stack_item and pop_stack_item.
Done

>
>>> +/* Implement the push_dummy_call gdbarch method.  */
>>> +
>>> +static CORE_ADDR
>>> +csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
>>> +                 struct regcache *regcache, CORE_ADDR bp_addr,
>>> +                 int nargs, struct value **args, CORE_ADDR sp,
>>> +                 int struct_return, CORE_ADDR struct_addr)
>>> +{
> [...]
>>> +      arg_type = check_typedef (value_type (args[argnum]));
>>> +      len = TYPE_LENGTH (arg_type);
>>> +      val = value_contents (args[argnum]);
>
> I wonder if this can ever throw.
>
> In theory of course it can.  But maybe in practice it isn't possible?
> I don't know.
>
> The issue is, if it can throw, then the stack_items will be leaked.
> A way around that is to redo the stack as self-managing C++ objects and
> use a local std::vector or the like to hold them.
>
>>> +  /* Transfer the dummy stack frame to the target.  */
>>> +  while (si)
>>> +    {
>>> +      sp -= si->len;
>>> +      write_memory (sp, (const bfd_byte *) si->data, si->len);
>
> A similar consideration applies here.
I removed the push/pull_stack_item and instead introduced a vector as
you suggested.
>
>
> This all seems pretty reasonable to me.
If it is approved, is there any chance that patch can make it to 8.2
release?

Thanks,
Abid



--
2018-07-27  Jiangshuai Li  <[hidden email]>
            Hafiz Abid Qadeer  <[hidden email]>
            Don Breazeal  <[hidden email]>

        * csky-linux-tdep.c: New file.
        * csky-tdep.c: Likewise.
        * csky-tdep.h: Likewise.
        * Makefile.in (ALL_TARGET_OBS): Add csky-linux-tdep.o and
        csky-tdep.o.
        (HFILES_NO_SRCDIR): Add csky-tdep.h.
        (ALLDEPFILES): Add csky-linux-tdep.c and csky-tdep.c
        * configure.tgt: Add csky support.
---
 gdb/Makefile.in       |    5 +
 gdb/configure.tgt     |   11 +
 gdb/csky-linux-tdep.c |  263 ++++++
 gdb/csky-tdep.c       | 2307
+++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/csky-tdep.h       |  355 ++++++++
 5 files changed, 2941 insertions(+)
 create mode 100644 gdb/csky-linux-tdep.c
 create mode 100644 gdb/csky-tdep.c
 create mode 100644 gdb/csky-tdep.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8c744d70c0..9eb420f250 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -688,6 +688,8 @@ ALL_TARGET_OBS = \
        bsd-uthread.o \
        cris-linux-tdep.o \
        cris-tdep.o \
+       csky-linux-tdep.o \
+       csky-tdep.o \
        dicos-tdep.o \
        fbsd-tdep.o \
        frv-linux-tdep.o \
@@ -1207,6 +1209,7 @@ HFILES_NO_SRCDIR = \
        completer.h \
        cp-abi.h \
        cp-support.h \
+       csky-tdep.h \
        ctf.h \
        d-lang.h \
        darwin-nat.h \
@@ -2207,6 +2210,8 @@ ALLDEPFILES = \
        bfin-tdep.c \
        bsd-kvm.c \
        bsd-uthread.c \
+       csky-linux-tdep.c \
+       csky-tdep.c \
        darwin-nat.c \
        dicos-tdep.c \
        fbsd-nat.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index f197160896..d2cd20dbcd 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -206,6 +206,17 @@ cris*)
        gdb_target_obs="cris-tdep.o cris-linux-tdep.o linux-tdep.o solib-svr4.o"
        ;;

+csky*-*-linux*)
+       # Target: CSKY running GNU/Linux
+       gdb_target_obs="csky-tdep.o csky-linux-tdep.o glibc-tdep.o \
+                       linux-tdep.o solib-svr4.o"
+       ;;
+
+csky*-*-*)
+       # Target: CSKY bare metal
+       gdb_target_obs="csky-tdep.o"
+       ;;
+
 frv-*-*)
        # Target: Fujitsu FRV processor
        gdb_target_obs="frv-tdep.o frv-linux-tdep.o linux-tdep.o solib-frv.o"
diff --git a/gdb/csky-linux-tdep.c b/gdb/csky-linux-tdep.c
new file mode 100644
index 0000000000..9e3ec393c8
--- /dev/null
+++ b/gdb/csky-linux-tdep.c
@@ -0,0 +1,263 @@
+/* Target-dependent code for GNU/Linux on CSKY.
+
+   Copyright (C) 2012-2018 Free Software Foundation, Inc.
+
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   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 "osabi.h"
+#include "glibc-tdep.h"
+#include "linux-tdep.h"
+#include "gdbarch.h"
+#include "solib-svr4.h"
+#include "regset.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+#include "csky-tdep.h"
+
+/* Functions, definitions, and data structures for C-Sky core file
debug.  */
+
+/* General regset pc, r1, r0, psr, r2-r31 for CK810.  */
+#define SIZEOF_CSKY_GREGSET 34*4
+/* Float regset fesr fsr fr0-fr31 for CK810.  */
+#define SIZEOF_CSKY_FREGSET 34*4
+
+/* Offset mapping table from core_section to regcache of general
+   registers for ck810.  */
+static const int csky_gregset_offset[] =
+{
+  72,  1,  0, 89,  2,  /* pc, r1, r0, psr, r2.  */
+   3,  4,  5,  6,  7,  /* r3 ~ r32.  */
+   8,  9, 10, 11, 12,
+  13, 14, 15, 16, 17,
+  18, 19, 20, 21, 22,
+  23, 24, 25, 26, 27,
+  28, 29, 30, 31
+};
+
+/* Offset mapping table from core_section to regcache of float
+   registers for ck810.  */
+
+static const int csky_fregset_offset[] =
+{
+  122, 123, 40, 41, 42,     /* fcr, fesr, fr0 ~ fr2.  */
+   43,  44, 45, 46, 47,     /* fr3 ~ fr15.  */
+   48,  49, 50, 51, 52,
+   53,  54, 55
+};
+
+/* Implement the supply_regset hook for GP registers in core files.  */
+
+static void
+csky_supply_gregset (const struct regset *regset,
+                    struct regcache *regcache, int regnum,
+                    const void *regs, size_t len)
+{
+  int i, gregset_num;
+  const gdb_byte *gregs = (const gdb_byte *) regs ;
+
+  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
+  gregset_num = ARRAY_SIZE (csky_gregset_offset);
+
+  for (i = 0; i < gregset_num; i++)
+    {
+      if ((regnum == csky_gregset_offset[i] || regnum == -1)
+         && csky_gregset_offset[i] != -1)
+       regcache->raw_supply (csky_gregset_offset[i], gregs + 4 * i);
+    }
+}
+
+/* Implement the collect_regset hook for GP registers in core files.  */
+
+static void
+csky_collect_gregset (const struct regset *regset,
+                     const struct regcache *regcache,
+                     int regnum, void *gregs_buf, size_t len)
+{
+  int regno, gregset_num;
+  gdb_byte *gregs = (gdb_byte *) gregs_buf ;
+
+  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
+  gregset_num = ARRAY_SIZE (csky_gregset_offset);
+
+  for (regno = 0; regno < gregset_num; regno++)
+    {
+      if ((regnum == csky_gregset_offset[regno] || regnum == -1)
+         && csky_gregset_offset[regno] != -1)
+       regcache->raw_collect (regno,
+                              gregs + 4 + csky_gregset_offset[regno]);
+    }
+}
+
+/* Implement the supply_regset hook for FP registers in core files.  */
+
+void
+csky_supply_fregset (const struct regset *regset,
+                    struct regcache *regcache, int regnum,
+                    const void *regs, size_t len)
+{
+  int i;
+  int offset = 0;
+  struct gdbarch *gdbarch = regcache->arch ();
+  const gdb_byte *fregs = (const gdb_byte *) regs;
+  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
+
+  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
+  for (i = 0; i < fregset_num; i++)
+    {
+      if ((regnum == csky_fregset_offset[i] || regnum == -1)
+         && csky_fregset_offset[i] != -1)
+       {
+         int num = csky_fregset_offset[i];
+         offset += register_size (gdbarch, num);
+         regcache->raw_supply (csky_fregset_offset[i], fregs + offset);
+       }
+    }
+}
+
+/* Implement the collect_regset hook for FP registers in core files.  */
+
+static void
+csky_collect_fregset (const struct regset *regset,
+                     const struct regcache *regcache,
+                     int regnum, void *fregs_buf, size_t len)
+{
+  int regno;
+  struct gdbarch *gdbarch = regcache->arch ();
+  gdb_byte *fregs = (gdb_byte *) fregs_buf ;
+  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
+  int offset = 0;
+
+  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
+  for (regno = 0; regno < fregset_num; regno++)
+    {
+      if ((regnum == csky_fregset_offset[regno] || regnum == -1)
+         && csky_fregset_offset[regno] != -1)
+       {
+         offset += register_size (gdbarch, csky_fregset_offset[regno]);
+         regcache->raw_collect (regno, fregs + offset);
+       }
+    }
+}
+
+static const struct regset csky_regset_general =
+{
+  NULL,
+  csky_supply_gregset,
+  csky_collect_gregset
+};
+
+static const struct regset csky_regset_float =
+{
+  NULL,
+  csky_supply_fregset,
+  csky_collect_fregset
+};
+
+/* Iterate over core file register note sections.  */
+
+static void
+csky_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                        iterate_over_regset_sections_cb *cb,
+                                        void *cb_data,
+                                        const struct regcache *regcache)
+{
+  cb (".reg", sizeof (csky_gregset_offset), &csky_regset_general,
+      NULL, cb_data);
+  cb (".reg2", sizeof (csky_fregset_offset), &csky_regset_float,
+      NULL, cb_data);
+}
+
+static void
+csky_linux_rt_sigreturn_init (const struct tramp_frame *self,
+                             struct frame_info *this_frame,
+                             struct trad_frame_cache *this_cache,
+                             CORE_ADDR func)
+{
+  int i;
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, 14);
+
+  CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE
+                  + CSKY_UCONTEXT_SIGCONTEXT
+                  + CSKY_SIGCONTEXT_SC_USP
+                  + CSKY_SIGCONTEXT_SC_A0;
+
+  /* Set addrs of R0 ~ R13.  */
+  for (i = 0; i < 14; i++)
+   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
+
+  /* Set addrs of SP(R14) and R15.  */
+  trad_frame_set_reg_addr (this_cache, 14, base - 4);
+  trad_frame_set_reg_addr (this_cache, 15, base + 4 * 14);
+
+  /* Set addrs of R16 ~ R31.  */
+  for (i = 15; i < 31; i++)
+   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
+
+  /* Set addrs of PSR and PC.  */
+  trad_frame_set_reg_addr (this_cache, 89, base + 4 * 33);
+  trad_frame_set_reg_addr (this_cache, 72, base + 4 * 34);
+
+  trad_frame_set_id (this_cache, frame_id_build (sp, func));
+}
+
+static struct tramp_frame
+csky_linux_rt_sigreturn_tramp_frame = {
+  SIGTRAMP_FRAME,
+  4,
+  {
+    { CSKY_MOVI_R7_173, -1 },
+    { CSKY_TRAP_0, -1 },
+    { TRAMP_SENTINEL_INSN }
+  },
+  csky_linux_rt_sigreturn_init
+};
+
+/* Hook function for gdbarch_register_osabi.  */
+
+static void
+csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  linux_init_abi (info, gdbarch);
+
+  /* Shared library handling.  */
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+                                        svr4_ilp32_fetch_link_map_offsets);
+
+  /* Enable TLS support.  */
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+                                            svr4_fetch_objfile_link_map);
+
+  /* Core file support.  */
+  set_gdbarch_iterate_over_regset_sections (
+    gdbarch, csky_linux_iterate_over_regset_sections);
+
+  /* Append tramp frame unwinder for SIGNAL.  */
+
+  tramp_frame_prepend_unwinder (gdbarch,
+                               &csky_linux_rt_sigreturn_tramp_frame);
+}
+
+void
+_initialize_csky_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_csky, 0, GDB_OSABI_LINUX,
+                         csky_linux_init_abi);
+}
diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
new file mode 100644
index 0000000000..4ddadc7885
--- /dev/null
+++ b/gdb/csky-tdep.c
@@ -0,0 +1,2307 @@
+/* Target-dependent code for the CSKY architecture, for GDB.
+
+   Copyright (C) 2010-2018 Free Software Foundation, Inc.
+
+   Contributed by C-SKY Microsystems and Mentor Graphics.
+
+   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 "gdb_assert.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "block.h"
+#include "reggroups.h"
+#include "elf/csky.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "dis-asm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "infcall.h"
+#include "floatformat.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "dwarf2-frame.h"
+#include "user-regs.h"
+#include "valprint.h"
+#include "reggroups.h"
+#include "csky-tdep.h"
+#include "regset.h"
+#include "block.h"
+#include "opcode/csky.h"
+#include <algorithm>
+#include <vector>
+
+/* Control debugging information emitted in this file.  */
+static int csky_debug = 0;
+
+static struct reggroup *cr_reggroup;
+static struct reggroup *fr_reggroup;
+static struct reggroup *vr_reggroup;
+static struct reggroup *mmu_reggroup;
+static struct reggroup *prof_reggroup;
+
+/* Convenience function to print debug messages in prologue analysis.  */
+
+static void
+print_savedreg_msg (int regno, int offsets[], bool print_continuing)
+{
+  fprintf_unfiltered (gdb_stdlog, "csky: r%d saved at offset 0x%x\n",
+                     regno, offsets[regno]);
+  if (print_continuing)
+    fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+}
+
+/*  Check whether the instruction at ADDR is 16-bit or not.  */
+
+static int
+csky_pc_is_csky16 (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_byte target_mem[2];
+  int status;
+  unsigned int insn;
+  int ret = 1;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  status = target_read_memory (addr, target_mem, 2);
+  /* Assume a 16-bit instruction if we can't read memory.  */
+  if (status)
+    return 1;
+
+  /* Get instruction from memory.  */
+  insn = extract_unsigned_integer (target_mem, 2, byte_order);
+  if ((insn & CSKY_32_INSN_MASK) == CSKY_32_INSN_MASK)
+    ret = 0;
+  else if (insn == CSKY_BKPT_INSN)
+    {
+      /* Check for 32-bit bkpt instruction which is all 0.  */
+      status = target_read_memory (addr + 2, target_mem, 2);
+      if (status)
+       return 1;
+
+      insn = extract_unsigned_integer (target_mem, 2, byte_order);
+      if (insn == CSKY_BKPT_INSN)
+       ret = 0;
+    }
+  return ret;
+}
+
+/* Get one instruction at ADDR and store it in INSN.  Return 2 for
+   a 16-bit instruction or 4 for a 32-bit instruction.  */
+
+static int
+csky_get_insn (struct gdbarch *gdbarch, CORE_ADDR addr, unsigned int *insn)
+{
+  gdb_byte target_mem[2];
+  unsigned int insn_type;
+  int status;
+  int insn_len = 2;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  status = target_read_memory (addr, target_mem, 2);
+  if (status)
+    memory_error (TARGET_XFER_E_IO, addr);
+
+  insn_type = extract_unsigned_integer (target_mem, 2, byte_order);
+  if (CSKY_32_INSN_MASK == (insn_type & CSKY_32_INSN_MASK))
+    {
+      status = target_read_memory (addr + 2, target_mem, 2);
+      if (status)
+       memory_error (TARGET_XFER_E_IO, addr);
+      insn_type = ((insn_type << 16)
+                  | extract_unsigned_integer (target_mem, 2, byte_order));
+      insn_len = 4;
+    }
+  *insn = insn_type;
+  return insn_len;
+}
+
+/* Implement the read_pc gdbarch method.  */
+
+static CORE_ADDR
+csky_read_pc (readable_regcache *regcache)
+{
+  ULONGEST pc;
+  regcache->cooked_read (CSKY_PC_REGNUM, &pc);
+  return pc;
+}
+
+/* Implement the write_pc gdbarch method.  */
+
+static void
+csky_write_pc (regcache *regcache, CORE_ADDR val)
+{
+  regcache_cooked_write_unsigned (regcache, CSKY_PC_REGNUM, val);
+}
+
+/* Implement the unwind_sp gdbarch method.  */
+
+static CORE_ADDR
+csky_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, CSKY_SP_REGNUM);
+}
+
+/* C-Sky ABI register names.  */
+
+static const char *csky_register_names[] =
+{
+  /* General registers 0 - 31.  */
+  "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+  "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+
+  /* DSP hilo registers 36 and 37.  */
+  "",      "",    "",     "",     "hi",    "lo",   "",    "",
+
+  /* FPU/VPU general registers 40 - 71.  */
+  "fr0", "fr1", "fr2",  "fr3",  "fr4",  "fr5",  "fr6",  "fr7",
+  "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+  "vr0", "vr1", "vr2",  "vr3",  "vr4",  "vr5",  "vr6",  "vr7",
+  "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15",
+
+  /* Program counter 72.  */
+  "pc",
+
+  /* Optional registers (ar) 73 - 88.  */
+  "ar0", "ar1", "ar2",  "ar3",  "ar4",  "ar5",  "ar6",  "ar7",
+  "ar8", "ar9", "ar10", "ar11", "ar12", "ar13", "ar14", "ar15",
+
+  /* Control registers (cr) 89 - 119.  */
+  "psr",  "vbr",  "epsr", "fpsr", "epc",  "fpc",  "ss0",  "ss1",
+  "ss2",  "ss3",  "ss4",  "gcr",  "gsr",  "cr13", "cr14", "cr15",
+  "cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
+  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
+
+  /* FPU/VPU control registers 121 ~ 123.  */
+  /* User sp 127.  */
+  "fid", "fcr", "fesr", "", "", "", "usp",
+
+  /* MMU control registers: 128 - 136.  */
+  "mcr0", "mcr2", "mcr3", "mcr4", "mcr6", "mcr8", "mcr29", "mcr30",
+  "mcr31", "", "", "",
+
+  /* Profiling control registers 140 - 143.  */
+  /* Profiling software general registers 144 - 157.  */
+  "profcr0",  "profcr1",  "profcr2",  "profcr3",  "profsgr0",  "profsgr1",
+  "profsgr2", "profsgr3", "profsgr4", "profsgr5", "profsgr6",  "profsgr7",
+  "profsgr8", "profsgr9", "profsgr10","profsgr11","profsgr12", "profsgr13",
+  "",   "",
+
+  /* Profiling architecture general registers 160 - 174.  */
+  "profagr0", "profagr1", "profagr2", "profagr3", "profagr4", "profagr5",
+  "profagr6", "profagr7", "profagr8", "profagr9", "profagr10","profagr11",
+  "profagr12","profagr13","profagr14", "",
+
+  /* Profiling extension general registers 176 - 188.  */
+  "profxgr0", "profxgr1", "profxgr2", "profxgr3", "profxgr4", "profxgr5",
+  "profxgr6", "profxgr7", "profxgr8", "profxgr9", "profxgr10","profxgr11",
+  "profxgr12",
+
+  /* Control registers in bank1.  */
+  "", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", "",
+  "cp1cr16", "cp1cr17", "cp1cr18", "cp1cr19", "cp1cr20", "", "", "",
+  "", "", "", "", "", "", "", "",
+
+  /* Control registers in bank3 (ICE).  */
+  "sepsr", "sevbr", "seepsr", "", "seepc", "", "nsssp", "seusp",
+  "sedcr", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", "",
+  "", "", "", "", "", "", "", ""
+};
+
+/* Implement the register_name gdbarch method.  */
+
+static const char *
+csky_register_name (struct gdbarch *gdbarch, int reg_nr)
+{
+  int csky_total_regnum;
+
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return tdesc_register_name (gdbarch, reg_nr);
+
+  if (reg_nr < 0)
+    return NULL;
+
+  if (reg_nr >= gdbarch_num_regs (gdbarch))
+    return NULL;
+
+  return csky_register_names[reg_nr];
+}
+
+/* Construct vector type for vrx registers.  */
+
+static struct type *
+csky_vector_type (struct gdbarch *gdbarch)
+{
+  const struct builtin_type *bt = builtin_type (gdbarch);
+
+  struct type *t;
+
+  t = arch_composite_type (gdbarch, "__gdb_builtin_type_vec128i",
+                          TYPE_CODE_UNION);
+
+  append_composite_type_field (t, "u32",
+                              init_vector_type (bt->builtin_int32, 4));
+  append_composite_type_field (t, "u16",
+                              init_vector_type (bt->builtin_int16, 8));
+  append_composite_type_field (t, "u8",
+                              init_vector_type (bt->builtin_int8, 16));
+
+  TYPE_VECTOR (t) = 1;
+  TYPE_NAME (t) = "builtin_type_vec128i";
+
+  return t;
+}
+
+/* Return the GDB type object for the "standard" data type
+   of data in register N.  */
+
+static struct type *
+csky_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  int num_regs = gdbarch_num_regs (gdbarch);
+  int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
+
+  /* PC, EPC, FPC is a text pointer.  */
+  if ((reg_nr == CSKY_PC_REGNUM)  || (reg_nr == CSKY_EPC_REGNUM)
+      || (reg_nr == CSKY_FPC_REGNUM))
+    return builtin_type (gdbarch)->builtin_func_ptr;
+
+  /* VBR is a data pointer.  */
+  if (reg_nr == CSKY_VBR_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+
+  /* Float register has 64 bits, and only in ck810.  */
+  if ((reg_nr >=CSKY_FR0_REGNUM) && (reg_nr <= CSKY_FR0_REGNUM + 15))
+      return arch_float_type (gdbarch, 64, "builtin_type_csky_ext",
+                             floatformats_ieee_double);
+
+  /* Vector register has 128 bits, and only in ck810.  */
+  if ((reg_nr >= CSKY_VR0_REGNUM) && (reg_nr <= CSKY_VR0_REGNUM + 15))
+    return csky_vector_type (gdbarch);
+
+  /* Profiling general register has 48 bits, we use 64bit.  */
+  if ((reg_nr >= CSKY_PROFGR_REGNUM) && (reg_nr <= CSKY_PROFGR_REGNUM +
44))
+    return builtin_type (gdbarch)->builtin_uint64;
+
+  if (reg_nr == CSKY_SP_REGNUM)
+    return builtin_type (gdbarch)->builtin_data_ptr;
+
+  /* Others are 32 bits.  */
+  return builtin_type (gdbarch)->builtin_int32;
+}
+
+/* Data structure to marshall items in a dummy stack frame when
+   calling a function in the inferior.  */
+
+struct stack_item
+{
+  stack_item (int len_, const gdb_byte *data_)
+  : len (len_), data (data_)
+  {}
+
+  int len;
+  const gdb_byte *data;
+};
+
+/* Implement the push_dummy_call gdbarch method.  */
+
+static CORE_ADDR
+csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+                     struct regcache *regcache, CORE_ADDR bp_addr,
+                     int nargs, struct value **args, CORE_ADDR sp,
+                     int struct_return, CORE_ADDR struct_addr)
+{
+  int argnum;
+  int argreg = CSKY_ABI_A0_REGNUM;
+  int last_arg_regnum = CSKY_ABI_LAST_ARG_REGNUM;
+  int need_dummy_stack = 0;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  std::vector<stack_item> stack_items;
+
+  /* Set the return address.  For CSKY, the return breakpoint is
+     always at BP_ADDR.  */
+  regcache_cooked_write_unsigned (regcache, CSKY_LR_REGNUM, bp_addr);
+
+  /* The struct_return pointer occupies the first parameter
+     passing register.  */
+  if (struct_return)
+    {
+      if (csky_debug)
+       {
+         fprintf_unfiltered (gdb_stdlog,
+                             "csky: struct return in %s = %s\n",
+                             gdbarch_register_name (gdbarch, argreg),
+                             paddress (gdbarch, struct_addr));
+       }
+      regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
+      argreg++;
+    }
+
+  /* Put parameters into argument registers in REGCACHE.
+     In ABI argument registers are r0 through r3.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      int len;
+      struct type *arg_type;
+      const gdb_byte *val;
+
+      arg_type = check_typedef (value_type (args[argnum]));
+      len = TYPE_LENGTH (arg_type);
+      val = value_contents (args[argnum]);
+
+      /* Copy the argument to argument registers or the dummy stack.
+        Large arguments are split between registers and stack.
+
+        If len < 4, there is no need to worry about endianness since
+        the arguments will always be stored in the low address.  */
+      if (len < 4)
+       {
+         CORE_ADDR regval
+           = extract_unsigned_integer (val, len, byte_order);
+         regcache_cooked_write_unsigned (regcache, argreg, regval);
+         argreg++;
+       }
+      else
+       {
+         while (len > 0)
+           {
+             int partial_len = len < 4 ? len : 4;
+             if (argreg <= last_arg_regnum)
+               {
+                 /* The argument is passed in an argument register.  */
+                 CORE_ADDR regval
+                   = extract_unsigned_integer (val, partial_len,
+                                               byte_order);
+                 if (byte_order == BFD_ENDIAN_BIG)
+                   regval <<= (4 - partial_len) * 8;
+
+                 /* Put regval into register in REGCACHE.  */
+                 regcache_cooked_write_unsigned (regcache, argreg,
+                                                 regval);
+                 argreg++;
+               }
+             else
+               {
+                 /* The argument should be pushed onto the dummy stack.  */
+                 stack_items.emplace_back (4, val);
+                 need_dummy_stack += 4;
+               }
+             len -= partial_len;
+             val += partial_len;
+           }
+       }
+    }
+
+  /* Transfer the dummy stack frame to the target.  */
+  std::vector<stack_item>::reverse_iterator iter;
+  for (iter = stack_items.rbegin (); iter != stack_items.rend (); ++iter)
+    {
+      sp -= iter->len;
+      write_memory (sp, iter->data, iter->len);
+    }
+
+  /* Finally, update the SP register.  */
+  regcache_cooked_write_unsigned (regcache, CSKY_SP_REGNUM, sp);
+  return sp;
+}
+
+/* Implement the return_value gdbarch method.  */
+
+static enum return_value_convention
+csky_return_value (struct gdbarch *gdbarch, struct value *function,
+                  struct type *valtype, struct regcache *regcache,
+                  gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  CORE_ADDR regval;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int len = TYPE_LENGTH (valtype);
+  unsigned int ret_regnum = CSKY_RET_REGNUM;
+
+  /* Csky abi specifies that return values larger than 8 bytes
+     are put on the stack.  */
+  if (len > 8)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+  else
+    {
+      if (readbuf != NULL)
+       {
+         ULONGEST tmp;
+         /* By using store_unsigned_integer we avoid having to do
+            anything special for small big-endian values.  */
+         regcache->cooked_read (ret_regnum, &tmp);
+         store_unsigned_integer (readbuf, (len > 4 ? 4 : len),
+                                 byte_order, tmp);
+         if (len > 4)
+           {
+             regcache->cooked_read (ret_regnum + 1, &tmp);
+             store_unsigned_integer (readbuf + 4,  4, byte_order, tmp);
+           }
+       }
+      if (writebuf != NULL)
+       {
+         regval = extract_unsigned_integer (writebuf, len > 4 ? 4 : len,
+                                            byte_order);
+         regcache_cooked_write_unsigned (regcache, ret_regnum, regval);
+         if (len > 4)
+           {
+             regval = extract_unsigned_integer ((gdb_byte *) writebuf + 4,
+                                                4, byte_order);
+             regcache_cooked_write_unsigned (regcache, ret_regnum + 1,
+                                             regval);
+           }
+
+       }
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+}
+
+/* Implement the frame_align gdbarch method.
+
+   Adjust the address downward (direction of stack growth) so that it
+   is correctly aligned for a new stack frame.  */
+
+static CORE_ADDR
+csky_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 4);
+}
+
+/* Unwind cache used for gdbarch fallback unwinder.  */
+
+struct csky_unwind_cache
+{
+  /* The stack pointer at the time this frame was created; i.e. the
+     caller's stack pointer when this function was called.  It is used
+     to identify this frame.  */
+  CORE_ADDR prev_sp;
+
+  /* The frame base for this frame is just prev_sp - frame size.
+     FRAMESIZE is the distance from the frame pointer to the
+     initial stack pointer.  */
+  int framesize;
+
+  /* The register used to hold the frame pointer for this frame.  */
+  int framereg;
+
+  /* Saved register offsets.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Do prologue analysis, returning the PC of the first instruction
+   after the function prologue.  */
+
+static CORE_ADDR
+csky_analyze_prologue (struct gdbarch *gdbarch,
+                      CORE_ADDR start_pc,
+                      CORE_ADDR limit_pc,
+                      CORE_ADDR end_pc,
+                      struct frame_info *this_frame,
+                      struct csky_unwind_cache *this_cache,
+                      lr_type_t lr_type)
+{
+  CORE_ADDR addr;
+  CORE_ADDR sp;
+  CORE_ADDR stack_size;
+  unsigned int insn, rn;
+  int status;
+  int flags;
+  int framesize = 0;
+  int stacksize = 0;
+  int register_offsets[CSKY_NUM_GREGS_SAVED_GREGS];
+  int insn_len;
+  /* For adjusting fp.  */
+  int is_fp_saved = 0;
+  int adjust_fp = 0;
+
+  /* REGISTER_OFFSETS will contain offsets from the top of the frame
+     (NOT the frame pointer) for the various saved registers, or -1
+     if the register is not saved.  */
+  for (rn = 0; rn < CSKY_NUM_GREGS_SAVED_GREGS; rn++)
+    register_offsets[rn] = -1;
+
+  /* Analyze the prologue.  Things we determine from analyzing the
+     prologue include the size of the frame and which registers are
+     saved (and where).  */
+  if (csky_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "csky: Scanning prologue: start_pc = 0x%x,"
+                         "limit_pc = 0x%x\n", (unsigned int) start_pc,
+                         (unsigned int) limit_pc);
+    }
+
+  /* Default to 16 bit instruction.  */
+  insn_len = 2;
+  stacksize = 0;
+  for (addr = start_pc; addr < limit_pc; addr += insn_len)
+    {
+      /* Get next insn.  */
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+
+      /* Check if 32 bit.  */
+      if (insn_len == 4)
+       {
+         /* subi32 sp,sp oimm12.  */
+         if (CSKY_32_IS_SUBI0 (insn))
+           {
+             /* Got oimm12.  */
+             int offset = CSKY_32_SUBI_IMM (insn);
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: got subi sp,%d; continuing\n",
+                                     offset);
+               }
+             stacksize += offset;
+             continue;
+           }
+         /* stm32 ry-rz,(sp).  */
+         else if (CSKY_32_IS_STMx0 (insn))
+           {
+             /* Spill register(s).  */
+             int start_register;
+             int reg_count;
+             int offset;
+
+             /* BIG WARNING! The CKCore ABI does not restrict functions
+                to taking only one stack allocation.  Therefore, when
+                we save a register, we record the offset of where it was
+                saved relative to the current stacksize.  This will
+                then give an offset from the SP upon entry to our
+                function.  Remember, stacksize is NOT constant until
+                we're done scanning the prologue.  */
+             start_register = CSKY_32_STM_VAL_REGNUM (insn);
+             reg_count = CSKY_32_STM_SIZE (insn);
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: got stm r%d-r%d,(sp)\n",
+                                     start_register,
+                                     start_register + reg_count);
+               }
+
+             for (rn = start_register, offset = 0;
+                  rn <= start_register + reg_count;
+                  rn++, offset += 4)
+               {
+                 register_offsets[rn] = stacksize - offset;
+                 if (csky_debug)
+                   {
+                     fprintf_unfiltered (gdb_stdlog,
+                                         "csky: r%d saved at 0x%x"
+                                         " (offset %d)\n",
+                                         rn, register_offsets[rn],
+                                         offset);
+                   }
+               }
+             if (csky_debug)
+               fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+             continue;
+           }
+         /* stw ry,(sp,disp).  */
+         else if (CSKY_32_IS_STWx0 (insn))
+           {
+             /* Spill register: see note for IS_STM above.  */
+             int disp;
+
+             rn = CSKY_32_ST_VAL_REGNUM (insn);
+             disp = CSKY_32_ST_OFFSET (insn);
+             register_offsets[rn] = stacksize - disp;
+             if (csky_debug)
+               print_savedreg_msg (rn, register_offsets, true);
+             continue;
+           }
+         else if (CSKY_32_IS_MOV_FP_SP (insn))
+           {
+             /* SP is saved to FP reg, means code afer prologue may
+                modify SP.  */
+             is_fp_saved = 1;
+             adjust_fp = stacksize;
+             continue;
+           }
+         else if (CSKY_32_IS_MFCR_EPSR (insn))
+           {
+             unsigned int insn2;
+             addr += 4;
+             int mfcr_regnum = insn & 0x1f;
+             insn_len = csky_get_insn (gdbarch, addr, &insn2);
+             if (insn_len == 2)
+               {
+                 int stw_regnum = (insn2 >> 5) & 0x7;
+                 if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+                   {
+                     int offset;
+
+                     /* CSKY_EPSR_REGNUM.  */
+                     rn  = CSKY_NUM_GREGS;
+                     offset = CSKY_16_STWx0_OFFSET (insn2);
+                     register_offsets[rn] = stacksize - offset;
+                     if (csky_debug)
+                       print_savedreg_msg (rn, register_offsets, true);
+                     continue;
+                   }
+                 break;
+               }
+             else
+               {
+                 /* INSN_LEN == 4.  */
+                 int stw_regnum = (insn2 >> 21) & 0x1f;
+                 if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+                   {
+                     int offset;
+
+                     /* CSKY_EPSR_REGNUM.  */
+                     rn  = CSKY_NUM_GREGS;
+                     offset = CSKY_32_ST_OFFSET (insn2);
+                     register_offsets[rn] = framesize - offset;
+                     if (csky_debug)
+                       print_savedreg_msg (rn, register_offsets, true);
+                     continue;
+                   }
+                 break;
+               }
+           }
+         else if (CSKY_32_IS_MFCR_FPSR (insn))
+           {
+             unsigned int insn2;
+             addr += 4;
+             int mfcr_regnum = insn & 0x1f;
+             insn_len = csky_get_insn (gdbarch, addr, &insn2);
+             if (insn_len == 2)
+               {
+                 int stw_regnum = (insn2 >> 5) & 0x7;
+                 if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum
+                                                == stw_regnum))
+                   {
+                     int offset;
+
+                     /* CSKY_FPSR_REGNUM.  */
+                     rn  = CSKY_NUM_GREGS + 1;
+                     offset = CSKY_16_STWx0_OFFSET (insn2);
+                     register_offsets[rn] = stacksize - offset;
+                     if (csky_debug)
+                       print_savedreg_msg (rn, register_offsets, true);
+                     continue;
+                   }
+                 break;
+               }
+             else
+               {
+                 /* INSN_LEN == 4.  */
+                 int stw_regnum = (insn2 >> 21) & 0x1f;
+                 if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+                   {
+                     int offset;
+
+                     /* CSKY_FPSR_REGNUM.  */
+                     rn  = CSKY_NUM_GREGS + 1;
+                     offset = CSKY_32_ST_OFFSET (insn2);
+                     register_offsets[rn] = framesize - offset;
+                     if (csky_debug)
+                       print_savedreg_msg (rn, register_offsets, true);
+                     continue;
+                   }
+                 break;
+               }
+           }
+         else if (CSKY_32_IS_MFCR_EPC (insn))
+           {
+             unsigned int insn2;
+             addr += 4;
+             int mfcr_regnum = insn & 0x1f;
+             insn_len = csky_get_insn (gdbarch, addr, &insn2);
+             if (insn_len == 2)
+               {
+                 int stw_regnum = (insn2 >> 5) & 0x7;
+                 if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+                   {
+                     int offset;
+
+                     /* CSKY_EPC_REGNUM.  */
+                     rn  = CSKY_NUM_GREGS + 2;
+                     offset = CSKY_16_STWx0_OFFSET (insn2);
+                     register_offsets[rn] = stacksize - offset;
+                     if (csky_debug)
+                       print_savedreg_msg (rn, register_offsets, true);
+                     continue;
+                   }
+                 break;
+               }
+             else
+               {
+                 /* INSN_LEN == 4.  */
+                 int stw_regnum = (insn2 >> 21) & 0x1f;
+                 if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+                   {
+                     int offset;
+
+                     /* CSKY_EPC_REGNUM.  */
+                     rn  = CSKY_NUM_GREGS + 2;
+                     offset = CSKY_32_ST_OFFSET (insn2);
+                     register_offsets[rn] = framesize - offset;
+                     if (csky_debug)
+                       print_savedreg_msg (rn, register_offsets, true);
+                     continue;
+                   }
+                 break;
+               }
+           }
+         else if (CSKY_32_IS_MFCR_FPC (insn))
+           {
+             unsigned int insn2;
+             addr += 4;
+             int mfcr_regnum = insn & 0x1f;
+             insn_len = csky_get_insn (gdbarch, addr, &insn2);
+             if (insn_len == 2)
+               {
+                 int stw_regnum = (insn2 >> 5) & 0x7;
+                 if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+                   {
+                     int offset;
+
+                     /* CSKY_FPC_REGNUM.  */
+                     rn  = CSKY_NUM_GREGS + 3;
+                     offset = CSKY_16_STWx0_OFFSET (insn2);
+                     register_offsets[rn] = stacksize - offset;
+                     if (csky_debug)
+                       print_savedreg_msg (rn, register_offsets, true);
+                     continue;
+                   }
+                 break;
+               }
+             else
+               {
+                 /* INSN_LEN == 4.  */
+                 int stw_regnum = (insn2 >> 21) & 0x1f;
+                 if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
+                   {
+                     int offset;
+
+                     /* CSKY_FPC_REGNUM.  */
+                     rn  = CSKY_NUM_GREGS + 3;
+                     offset = CSKY_32_ST_OFFSET (insn2);
+                     register_offsets[rn] = framesize - offset;
+                     if (csky_debug)
+                       print_savedreg_msg (rn, register_offsets, true);
+                     continue;
+                   }
+                 break;
+               }
+           }
+         else if (CSKY_32_IS_PUSH (insn))
+           {
+             /* Push for 32_bit.  */
+             int offset = 0;
+             if (CSKY_32_IS_PUSH_R29 (insn))
+               {
+                 stacksize += 4;
+                 register_offsets[29] = stacksize;
+                 if (csky_debug)
+                   print_savedreg_msg (29, register_offsets, false);
+                 offset += 4;
+               }
+             if (CSKY_32_PUSH_LIST2 (insn))
+               {
+                 int num = CSKY_32_PUSH_LIST2 (insn);
+                 int tmp = 0;
+                 stacksize += num * 4;
+                 offset += num * 4;
+                 if (csky_debug)
+                   {
+                     fprintf_unfiltered (gdb_stdlog,
+                                         "csky: push regs_array: r16-r%d\n",
+                                         16 + num - 1);
+                   }
+                 for (rn = 16; rn <= 16 + num - 1; rn++)
+                   {
+                      register_offsets[rn] = stacksize - tmp;
+                      if (csky_debug)
+                        {
+                          fprintf_unfiltered (gdb_stdlog,
+                                              "csky: r%d saved at 0x%x"
+                                              " (offset %d)\n", rn,
+                                              register_offsets[rn], tmp);
+                        }
+                      tmp += 4;
+                   }
+               }
+             if (CSKY_32_IS_PUSH_R15 (insn))
+               {
+                 stacksize += 4;
+                 register_offsets[15] = stacksize;
+                 if (csky_debug)
+                   print_savedreg_msg (15, register_offsets, false);
+                 offset += 4;
+               }
+             if (CSKY_32_PUSH_LIST1 (insn))
+               {
+                 int num = CSKY_32_PUSH_LIST1 (insn);
+                 int tmp = 0;
+                 stacksize += num * 4;
+                 offset += num * 4;
+                 if (csky_debug)
+                   {
+                     fprintf_unfiltered (gdb_stdlog,
+                                         "csky: push regs_array: r4-r%d\n",
+                                         4 + num - 1);
+                   }
+                 for (rn = 4; rn <= 4 + num - 1; rn++)
+                   {
+                      register_offsets[rn] = stacksize - tmp;
+                      if (csky_debug)
+                        {
+                          fprintf_unfiltered (gdb_stdlog,
+                                              "csky: r%d saved at 0x%x"
+                                              " (offset %d)\n", rn,
+                                              register_offsets[rn], tmp);
+                        }
+                       tmp += 4;
+                   }
+               }
+
+             framesize = stacksize;
+             if (csky_debug)
+               fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+             continue;
+           }
+         else if (CSKY_32_IS_LRW4 (insn) || CSKY_32_IS_MOVI4 (insn)
+                  || CSKY_32_IS_MOVIH4 (insn) || CSKY_32_IS_BMASKI4 (insn))
+           {
+             int adjust = 0;
+             int offset = 0;
+             unsigned int insn2;
+
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: looking at large frame\n");
+               }
+             if (CSKY_32_IS_LRW4 (insn))
+               {
+                 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+                 int literal_addr = (addr + ((insn & 0xffff) << 2))
+                                    & 0xfffffffc;
+                 adjust = read_memory_unsigned_integer (literal_addr, 4,
+                                                        byte_order);
+               }
+             else if (CSKY_32_IS_MOVI4 (insn))
+               adjust = (insn  & 0xffff);
+             else if (CSKY_32_IS_MOVIH4 (insn))
+               adjust = (insn & 0xffff) << 16;
+             else
+               {
+                 /* CSKY_32_IS_BMASKI4 (insn).  */
+                 adjust = (1 << (((insn & 0x3e00000) >> 21) + 1)) - 1;
+               }
+
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: base stacksize=0x%x\n", adjust);
+
+                 /* May have zero or more insns which modify r4.  */
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: looking for r4 adjusters...\n");
+               }
+
+             offset = 4;
+             insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+             while (CSKY_IS_R4_ADJUSTER (insn2))
+               {
+                 if (CSKY_32_IS_ADDI4 (insn2))
+                   {
+                     int imm = (insn2 & 0xfff) + 1;
+                     adjust += imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: addi r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_SUBI4 (insn2))
+                   {
+                     int imm = (insn2 & 0xfff) + 1;
+                     adjust -= imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: subi r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_NOR4 (insn2))
+                   {
+                     adjust = ~adjust;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: nor r4,r4,r4\n");
+                       }
+                   }
+                 else if (CSKY_32_IS_ROTLI4 (insn2))
+                   {
+                     int imm = ((insn2 >> 21) & 0x1f);
+                     int temp = adjust >> (32 - imm);
+                     adjust <<= imm;
+                     adjust |= temp;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: rotli r4,r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_LISI4 (insn2))
+                   {
+                     int imm = ((insn2 >> 21) & 0x1f);
+                     adjust <<= imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: lsli r4,r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_BSETI4 (insn2))
+                   {
+                     int imm = ((insn2 >> 21) & 0x1f);
+                     adjust |= (1 << imm);
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: bseti r4,r4 %d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_BCLRI4 (insn2))
+                   {
+                     int imm = ((insn2 >> 21) & 0x1f);
+                     adjust &= ~(1 << imm);
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: bclri r4,r4 %d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_IXH4 (insn2))
+                   {
+                     adjust *= 3;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: ixh r4,r4,r4\n");
+                       }
+                   }
+                 else if (CSKY_32_IS_IXW4 (insn2))
+                   {
+                     adjust *= 5;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: ixw r4,r4,r4\n");
+                       }
+                   }
+                 else if (CSKY_16_IS_ADDI4 (insn2))
+                   {
+                     int imm = (insn2 & 0xff) + 1;
+                     adjust += imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: addi r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_16_IS_SUBI4 (insn2))
+                   {
+                     int imm = (insn2 & 0xff) + 1;
+                     adjust -= imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: subi r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_16_IS_NOR4 (insn2))
+                   {
+                     adjust = ~adjust;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: nor r4,r4\n");
+                       }
+                   }
+                 else if (CSKY_16_IS_BSETI4 (insn2))
+                   {
+                     int imm = (insn2 & 0x1f);
+                     adjust |= (1 << imm);
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: bseti r4, %d\n", imm);
+                       }
+                   }
+                 else if (CSKY_16_IS_BCLRI4 (insn2))
+                   {
+                     int imm = (insn2 & 0x1f);
+                     adjust &= ~(1 << imm);
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: bclri r4, %d\n", imm);
+                       }
+                   }
+                 else if (CSKY_16_IS_LSLI4 (insn2))
+                   {
+                     int imm = (insn2 & 0x1f);
+                     adjust <<= imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: lsli r4,r4, %d\n", imm);
+                       }
+                   }
+
+                 offset += insn_len;
+                 insn_len =  csky_get_insn (gdbarch, addr + offset, &insn2);
+               };
+
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog, "csky: done looking for"
+                                     " r4 adjusters\n");
+               }
+
+             /* If the next insn adjusts the stack pointer, we keep
+                everything; if not, we scrap it and we've found the
+                end of the prologue.  */
+             if (CSKY_IS_SUBU4 (insn2))
+               {
+                 addr += offset;
+                 stacksize += adjust;
+                 if (csky_debug)
+                   {
+                     fprintf_unfiltered (gdb_stdlog,
+                                         "csky: found stack adjustment of"
+                                         " 0x%x bytes.\n", adjust);
+                     fprintf_unfiltered (gdb_stdlog,
+                                         "csky: skipping to new address "
+                                         "0x%lx\n", addr);
+                     fprintf_unfiltered (gdb_stdlog,
+                                         "csky: continuing\n");
+                   }
+                 continue;
+               }
+
+             /* None of these instructions are prologue, so don't touch
+                anything.  */
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: no subu sp,sp,r4; NOT altering"
+                                     " stacksize.\n");
+               }
+             break;
+           }
+       }
+      else
+       {
+         /* insn_len != 4.  */
+
+         /* subi.sp sp,disp.  */
+         if (CSKY_16_IS_SUBI0 (insn))
+           {
+             int offset = CSKY_16_SUBI_IMM (insn);
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: got subi r0,%d; continuing\n",
+                                     offset);
+               }
+             stacksize += offset;
+             continue;
+           }
+         /* stw.16 rz,(sp,disp).  */
+         else if (CSKY_16_IS_STWx0 (insn))
+           {
+             /* Spill register: see note for IS_STM above.  */
+             int disp;
+
+             rn = CSKY_16_ST_VAL_REGNUM (insn);
+             disp = CSKY_16_ST_OFFSET (insn);
+             register_offsets[rn] = stacksize - disp;
+             if (csky_debug)
+               print_savedreg_msg (rn, register_offsets, true);
+             continue;
+           }
+         else if (CSKY_16_IS_MOV_FP_SP (insn))
+           {
+             /* SP is saved to FP reg, means prologue may modify SP.  */
+             is_fp_saved = 1;
+             adjust_fp = stacksize;
+             continue;
+           }
+         else if (CSKY_16_IS_PUSH (insn))
+           {
+             /* Push for 16_bit.  */
+             int offset = 0;
+             if (CSKY_16_IS_PUSH_R15 (insn))
+               {
+                 stacksize += 4;
+                 register_offsets[15] = stacksize;
+                 if (csky_debug)
+                   print_savedreg_msg (15, register_offsets, false);
+                 offset += 4;
+                }
+             if (CSKY_16_PUSH_LIST1 (insn))
+               {
+                 int num = CSKY_16_PUSH_LIST1 (insn);
+                 int tmp = 0;
+                 stacksize += num * 4;
+                 offset += num * 4;
+                 if (csky_debug)
+                   {
+                     fprintf_unfiltered (gdb_stdlog,
+                                         "csky: push regs_array: r4-r%d\n",
+                                         4 + num - 1);
+                   }
+                 for (rn = 4; rn <= 4 + num - 1; rn++)
+                   {
+                      register_offsets[rn] = stacksize - tmp;
+                      if (csky_debug)
+                        {
+                          fprintf_unfiltered (gdb_stdlog,
+                                              "csky: r%d saved at 0x%x"
+                                              " (offset %d)\n", rn,
+                                              register_offsets[rn], offset);
+                        }
+                      tmp += 4;
+                   }
+               }
+
+             framesize = stacksize;
+             if (csky_debug)
+               fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+             continue;
+           }
+         else if (CSKY_16_IS_LRW4 (insn) || CSKY_16_IS_MOVI4 (insn))
+           {
+             int adjust = 0;
+             int offset = 0;
+             unsigned int insn2;
+
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: looking at large frame\n");
+               }
+             if (CSKY_16_IS_LRW4 (insn))
+               {
+                 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+                 int offset = ((insn & 0x300) >> 3) | (insn & 0x1f);
+                 int literal_addr = (addr + ( offset << 2)) & 0xfffffffc;
+                 adjust = read_memory_unsigned_integer (literal_addr, 4,
+                                                        byte_order);
+               }
+             else
+               {
+                 /* CSKY_16_IS_MOVI4 (insn).  */
+                 adjust = (insn  & 0xff);
+               }
+
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: base stacksize=0x%x\n", adjust);
+               }
+
+             /* May have zero or more instructions which modify r4.  */
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "csky: looking for r4 adjusters...\n");
+               }
+             offset = 2;
+             insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+             while (CSKY_IS_R4_ADJUSTER (insn2))
+               {
+                 if (CSKY_32_IS_ADDI4 (insn2))
+                   {
+                     int imm = (insn2 & 0xfff) + 1;
+                     adjust += imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: addi r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_SUBI4 (insn2))
+                   {
+                     int imm = (insn2 & 0xfff) + 1;
+                     adjust -= imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: subi r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_NOR4 (insn2))
+                   {
+                     adjust = ~adjust;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: nor r4,r4,r4\n");
+                       }
+                   }
+                 else if (CSKY_32_IS_ROTLI4 (insn2))
+                   {
+                     int imm = ((insn2 >> 21) & 0x1f);
+                     int temp = adjust >> (32 - imm);
+                     adjust <<= imm;
+                     adjust |= temp;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: rotli r4,r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_LISI4 (insn2))
+                   {
+                     int imm = ((insn2 >> 21) & 0x1f);
+                     adjust <<= imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: lsli r4,r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_BSETI4 (insn2))
+                   {
+                     int imm = ((insn2 >> 21) & 0x1f);
+                     adjust |= (1 << imm);
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: bseti r4,r4 %d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_BCLRI4 (insn2))
+                   {
+                     int imm = ((insn2 >> 21) & 0x1f);
+                     adjust &= ~(1 << imm);
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: bclri r4,r4 %d\n", imm);
+                       }
+                   }
+                 else if (CSKY_32_IS_IXH4 (insn2))
+                   {
+                     adjust *= 3;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: ixh r4,r4,r4\n");
+                       }
+                   }
+                 else if (CSKY_32_IS_IXW4 (insn2))
+                   {
+                     adjust *= 5;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: ixw r4,r4,r4\n");
+                       }
+                   }
+                 else if (CSKY_16_IS_ADDI4 (insn2))
+                   {
+                     int imm = (insn2 & 0xff) + 1;
+                     adjust += imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: addi r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_16_IS_SUBI4 (insn2))
+                   {
+                     int imm = (insn2 & 0xff) + 1;
+                     adjust -= imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: subi r4,%d\n", imm);
+                       }
+                   }
+                 else if (CSKY_16_IS_NOR4 (insn2))
+                   {
+                     adjust = ~adjust;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: nor r4,r4\n");
+                       }
+                   }
+                 else if (CSKY_16_IS_BSETI4 (insn2))
+                   {
+                     int imm = (insn2 & 0x1f);
+                     adjust |= (1 << imm);
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: bseti r4, %d\n", imm);
+                       }
+                   }
+                 else if (CSKY_16_IS_BCLRI4 (insn2))
+                   {
+                     int imm = (insn2 & 0x1f);
+                     adjust &= ~(1 << imm);
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: bclri r4, %d\n", imm);
+                       }
+                   }
+                 else if (CSKY_16_IS_LSLI4 (insn2))
+                   {
+                     int imm = (insn2 & 0x1f);
+                     adjust <<= imm;
+                     if (csky_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "csky: lsli r4,r4, %d\n", imm);
+                       }
+                   }
+
+                 offset += insn_len;
+                 insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
+               };
+
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog, "csky: "
+                                     "done looking for r4 adjusters\n");
+               }
+
+             /* If the next instruction adjusts the stack pointer, we keep
+                everything; if not, we scrap it and we've found the end
+                of the prologue.  */
+             if (CSKY_IS_SUBU4 (insn2))
+               {
+                 addr += offset;
+                 stacksize += adjust;
+                 if (csky_debug)
+                   {
+                     fprintf_unfiltered (gdb_stdlog, "csky: "
+                                         "found stack adjustment of 0x%x"
+                                         " bytes.\n", adjust);
+                     fprintf_unfiltered (gdb_stdlog, "csky: "
+                                         "skipping to new address 0x%lx\n",
+                                         addr);
+                     fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
+                   }
+                 continue;
+               }
+
+             /* None of these instructions are prologue, so don't touch
+                anything.  */
+             if (csky_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog, "csky: no subu sp,r4; "
+                                     "NOT altering stacksize.\n");
+               }
+             break;
+           }
+       }
+
+      /* This is not a prologue instruction, so stop here.  */
+      if (csky_debug)
+       {
+         fprintf_unfiltered (gdb_stdlog, "csky: insn is not a prologue"
+                             " insn -- ending scan\n");
+       }
+      break;
+    }
+
+  if (this_cache)
+    {
+      CORE_ADDR unwound_fp;
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      this_cache->framesize = framesize;
+
+      if (is_fp_saved)
+       {
+         this_cache->framereg = CSKY_FP_REGNUM;
+         unwound_fp = get_frame_register_unsigned (this_frame,
+                                                   this_cache->framereg);
+         this_cache->prev_sp = unwound_fp + adjust_fp;
+       }
+      else
+       {
+         this_cache->framereg = CSKY_SP_REGNUM;
+         unwound_fp = get_frame_register_unsigned (this_frame,
+                                                   this_cache->framereg);
+         this_cache->prev_sp = unwound_fp + stacksize;
+       }
+
+      /* Note where saved registers are stored.  The offsets in
+        REGISTER_OFFSETS are computed relative to the top of the frame.  */
+      for (rn = 0; rn < CSKY_NUM_GREGS; rn++)
+       {
+         if (register_offsets[rn] >= 0)
+           {
+             this_cache->saved_regs[rn].addr
+               = this_cache->prev_sp - register_offsets[rn];
+             if (csky_debug)
+               {
+                 CORE_ADDR rn_value = read_memory_unsigned_integer (
+                   this_cache->saved_regs[rn].addr, 4, byte_order);
+                 fprintf_unfiltered (gdb_stdlog, "Saved register %s "
+                                     "stored at 0x%08lx, value=0x%08lx\n",
+                                     csky_register_names[rn],
+                                     (unsigned long)
+                                       this_cache->saved_regs[rn].addr,
+                                     (unsigned long) rn_value);
+               }
+           }
+       }
+      if (lr_type == LR_TYPE_EPC)
+       {
+         /* rte || epc .  */
+         this_cache->saved_regs[CSKY_PC_REGNUM]
+           = this_cache->saved_regs[CSKY_EPC_REGNUM];
+       }
+      else if (lr_type == LR_TYPE_FPC)
+       {
+         /* rfi || fpc .  */
+         this_cache->saved_regs[CSKY_PC_REGNUM]
+           = this_cache->saved_regs[CSKY_FPC_REGNUM];
+       }
+      else
+       {
+         this_cache->saved_regs[CSKY_PC_REGNUM]
+           = this_cache->saved_regs[CSKY_LR_REGNUM];
+       }
+    }
+
+  return addr;
+}
+
+/* Detect whether PC is at a point where the stack frame has been
+   destroyed.  */
+
+static int
+csky_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  unsigned int insn;
+  CORE_ADDR addr;
+  CORE_ADDR func_start, func_end;
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  bool fp_saved = false;
+  int insn_len;
+  for (addr = func_start; addr < func_end; addr += insn_len)
+    {
+      /* Get next insn.  */
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+
+      if (insn_len == 2)
+       {
+         /* Is sp is saved to fp.  */
+         if (CSKY_16_IS_MOV_FP_SP (insn))
+           fp_saved = true;
+         /* If sp was saved to fp and now being restored from
+            fp then it indicates the start of epilog.  */
+         else if (fp_saved && CSKY_16_IS_MOV_SP_FP (insn))
+           return pc >= addr;
+       }
+    }
+  return 0;
+}
+
+/* Implement the skip_prologue gdbarch hook.  */
+
+static CORE_ADDR
+csky_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal;
+  LONGEST return_value;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  const int default_search_limit = 128;
+
+  /* See if we can find the end of the prologue using the symbol table.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    {
+      CORE_ADDR post_prologue_pc
+       = skip_prologue_using_sal (gdbarch, func_addr);
+
+      if (post_prologue_pc != 0)
+       return std::max (pc, post_prologue_pc);
+    }
+  else
+    func_end = pc + default_search_limit;
+
+  /* Find the end of prologue.  Default lr_type.  */
+  return csky_analyze_prologue (gdbarch, pc, func_end, func_end,
+                               NULL, NULL, LR_TYPE_R15);
+}
+
+/* Implement the breakpoint_kind_from_pc gdbarch method.  */
+
+static int
+csky_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+  if (csky_pc_is_csky16 (gdbarch, *pcptr))
+    return CSKY_INSN_SIZE16;
+  else
+    return CSKY_INSN_SIZE32;
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method.  */
+
+static const gdb_byte *
+csky_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+  *size = kind;
+  if (kind == CSKY_INSN_SIZE16)
+    {
+      static gdb_byte csky_16_breakpoint[] = { 0, 0 };
+      return csky_16_breakpoint;
+    }
+  else
+    {
+      static gdb_byte csky_32_breakpoint[] = { 0, 0, 0, 0 };
+      return csky_32_breakpoint;
+    }
+}
+
+/* Implement the memory_insert_breakpoint gdbarch method.  */
+
+static int
+csky_memory_insert_breakpoint (struct gdbarch *gdbarch,
+                              struct bp_target_info *bp_tgt)
+{
+  int val;
+  const unsigned char *bp;
+  gdb_byte bp_write_record1[] = { 0, 0, 0, 0 };
+  gdb_byte bp_write_record2[] = { 0, 0, 0, 0 };
+  gdb_byte bp_record[] = { 0, 0, 0, 0 };
+
+  /* Sanity-check bp_address.  */
+  if (bp_tgt->reqstd_address % 2)
+    warning (_("Invalid breakpoint address 0x%x is an odd number.\n"),
+            (unsigned int) bp_tgt->reqstd_address);
+  scoped_restore restore_memory
+    = make_scoped_restore_show_memory_breakpoints (1);
+
+  /* Determine appropriate breakpoint_kind for this address.  */
+  bp_tgt->kind = csky_breakpoint_kind_from_pc (gdbarch,
+                                              &bp_tgt->reqstd_address);
+
+  /* Save the memory contents.  */
+  bp_tgt->shadow_len = bp_tgt->kind;
+
+  /* Fill bp_tgt->placed_address.  */
+  bp_tgt->placed_address = bp_tgt->reqstd_address;
+
+  if (bp_tgt->kind == CSKY_INSN_SIZE16)
+    {
+      if ((bp_tgt->reqstd_address % 4) == 0)
+       {
+         /* Read two bytes.  */
+         val = target_read_memory (bp_tgt->reqstd_address,
+                                   bp_tgt->shadow_contents, 2);
+         if (val)
+           return val;
+
+         /* Read two bytes.  */
+         val = target_read_memory (bp_tgt->reqstd_address + 2,
+                                   bp_record, 2);
+         if (val)
+           return val;
+
+         /* Write the breakpoint.  */
+         bp_write_record1[2] = bp_record[0];
+         bp_write_record1[3] = bp_record[1];
+         bp = bp_write_record1;
+         val = target_write_raw_memory (bp_tgt->reqstd_address, bp,
+                                        CSKY_WR_BKPT_MODE);
+       }
+      else
+       {
+         val = target_read_memory (bp_tgt->reqstd_address,
+                                   bp_tgt->shadow_contents, 2);
+         if (val)
+           return val;
+
+         val = target_read_memory (bp_tgt->reqstd_address - 2,
+                                   bp_record, 2);
+         if (val)
+           return val;
+
+         /* Write the breakpoint.  */
+         bp_write_record1[0] = bp_record[0];
+         bp_write_record1[1] = bp_record[1];
+         bp = bp_write_record1;
+         val = target_write_raw_memory (bp_tgt->reqstd_address - 2,
+                                        bp, CSKY_WR_BKPT_MODE);
+       }
+    }
+  else
+    {
+      if (bp_tgt->placed_address % 4 == 0)
+       {
+         val = target_read_memory (bp_tgt->reqstd_address,
+                                   bp_tgt->shadow_contents,
+                                   CSKY_WR_BKPT_MODE);
+         if (val)
+           return val;
+
+         /* Write the breakpoint.  */
+         bp = bp_write_record1;
+         val = target_write_raw_memory (bp_tgt->reqstd_address,
+                                        bp, CSKY_WR_BKPT_MODE);
+       }
+      else
+       {
+         val = target_read_memory (bp_tgt->reqstd_address,
+                                   bp_tgt->shadow_contents,
+                                   CSKY_WR_BKPT_MODE);
+         if (val)
+           return val;
+
+         val = target_read_memory (bp_tgt->reqstd_address - 2,
+                                   bp_record, 2);
+         if (val)
+           return val;
+
+         val = target_read_memory (bp_tgt->reqstd_address + 4,
+                                   bp_record + 2, 2);
+         if (val)
+           return val;
+
+         bp_write_record1[0] = bp_record[0];
+         bp_write_record1[1] = bp_record[1];
+         bp_write_record2[2] = bp_record[2];
+         bp_write_record2[3] = bp_record[3];
+
+         /* Write the breakpoint.  */
+         bp = bp_write_record1;
+         val = target_write_raw_memory (bp_tgt->reqstd_address - 2, bp,
+                                        CSKY_WR_BKPT_MODE);
+         if (val)
+           return val;
+
+         /* Write the breakpoint.  */
+         bp = bp_write_record2;
+         val = target_write_raw_memory (bp_tgt->reqstd_address + 2, bp,
+                                        CSKY_WR_BKPT_MODE);
+       }
+    }
+  return val;
+}
+
+/* Restore the breakpoint shadow_contents to the target.  */
+
+static int
+csky_memory_remove_breakpoint (struct gdbarch *gdbarch,
+                              struct bp_target_info *bp_tgt)
+{
+  int val;
+  gdb_byte bp_record[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+  /* Different for shadow_len 2 or 4.  */
+  if (bp_tgt->shadow_len == 2)
+    {
+      /* Do word-sized writes on word-aligned boundaries and read
+        padding bytes as necessary.  */
+      if (bp_tgt->reqstd_address % 4 == 0)
+       {
+         val = target_read_memory (bp_tgt->reqstd_address + 2,
+                                   bp_record + 2, 2);
+         if (val)
+           return val;
+         bp_record[0] = bp_tgt->shadow_contents[0];
+         bp_record[1] = bp_tgt->shadow_contents[1];
+         return target_write_raw_memory (bp_tgt->reqstd_address,
+                                         bp_record, CSKY_WR_BKPT_MODE);
+       }
+      else
+       {
+         val = target_read_memory (bp_tgt->reqstd_address - 2,
+                                   bp_record, 2);
+         if (val)
+           return val;
+         bp_record[2] = bp_tgt->shadow_contents[0];
+         bp_record[3] = bp_tgt->shadow_contents[1];
+         return target_write_raw_memory (bp_tgt->reqstd_address - 2,
+                                         bp_record, CSKY_WR_BKPT_MODE);
+       }
+    }
+  else
+    {
+      /* Do word-sized writes on word-aligned boundaries and read
+        padding bytes as necessary.  */
+      if (bp_tgt->placed_address % 4 == 0)
+       {
+         return target_write_raw_memory (bp_tgt->reqstd_address,
+                                         bp_tgt->shadow_contents,
+                                         CSKY_WR_BKPT_MODE);
+       }
+      else
+       {
+         val = target_read_memory (bp_tgt->reqstd_address - 2,
+                                   bp_record, 2);
+         if (val)
+           return val;
+         val = target_read_memory (bp_tgt->reqstd_address + 4,
+                                   bp_record+6, 2);
+         if (val)
+           return val;
+
+         bp_record[2] = bp_tgt->shadow_contents[0];
+         bp_record[3] = bp_tgt->shadow_contents[1];
+         bp_record[4] = bp_tgt->shadow_contents[2];
+         bp_record[5] = bp_tgt->shadow_contents[3];
+
+         return target_write_raw_memory (bp_tgt->reqstd_address - 2,
+                                         bp_record,
+                                         CSKY_WR_BKPT_MODE * 2);
+       }
+    }
+}
+
+/* Determine link register type.  */
+
+static lr_type_t
+csky_analyze_lr_type (struct gdbarch *gdbarch,
+                     CORE_ADDR start_pc, CORE_ADDR end_pc)
+{
+  CORE_ADDR addr;
+  unsigned int insn, rn, insn_len;
+  insn_len = 2;
+
+  for (addr = start_pc; addr < end_pc; addr += insn_len)
+    {
+      insn_len = csky_get_insn (gdbarch, addr, &insn);
+      if (insn_len == 4)
+       {
+         if (CSKY_32_IS_MFCR_EPSR (insn) || CSKY_32_IS_MFCR_EPC (insn)
+             || CSKY_32_IS_RTE (insn))
+           return LR_TYPE_EPC;
+       }
+      else if (CSKY_32_IS_MFCR_FPSR (insn) || CSKY_32_IS_MFCR_FPC (insn)
+              || CSKY_32_IS_RFI (insn))
+       return LR_TYPE_FPC;
+      else if (CSKY_32_IS_JMP (insn) || CSKY_32_IS_BR (insn)
+              || CSKY_32_IS_JMPIX (insn) || CSKY_32_IS_JMPI (insn))
+       return LR_TYPE_R15;
+      else
+       {
+         /* 16 bit instruction.  */
+         if (CSKY_16_IS_JMP (insn) || CSKY_16_IS_BR (insn)
+             || CSKY_16_IS_JMPIX (insn))
+           return LR_TYPE_R15;
+       }
+    }
+    return LR_TYPE_R15;
+}
+
+/* Heuristic unwinder.  */
+
+static struct csky_unwind_cache *
+csky_frame_unwind_cache (struct frame_info *this_frame)
+{
+  CORE_ADDR prologue_start, prologue_end, func_end, prev_pc, block_addr;
+  struct csky_unwind_cache *cache;
+  const struct block *bl;
+  unsigned long func_size = 0;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  unsigned int sp_regnum = CSKY_SP_REGNUM;
+
+  /* Default lr type is r15.  */
+  lr_type_t lr_type = LR_TYPE_R15;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct csky_unwind_cache);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  /* Assume there is no frame until proven otherwise.  */
+  cache->framereg = sp_regnum;
+
+  cache->framesize = 0;
+
+  prev_pc = get_frame_pc (this_frame);
+  block_addr = get_frame_address_in_block (this_frame);
+  if (find_pc_partial_function (block_addr, NULL, &prologue_start,
+                               &func_end) == 0)
+    /* We couldn't find a function containing block_addr, so bail out
+       and hope for the best.  */
+    return cache;
+
+  /* Get the (function) symbol matching prologue_start.  */
+  bl = block_for_pc (prologue_start);
+  if (bl != NULL)
+    func_size = bl->endaddr - bl->startaddr;
+  else
+    {
+      struct bound_minimal_symbol msymbol
+       = lookup_minimal_symbol_by_pc (prologue_start);
+      if (msymbol.minsym != NULL)
+       func_size = MSYMBOL_SIZE (msymbol.minsym);
+    }
+
+  /* If FUNC_SIZE is 0 we may have a special-case use of lr
+     e.g. exception or interrupt.  */
+  if (func_size == 0)
+    lr_type = csky_analyze_lr_type (gdbarch, prologue_start, func_end);
+
+  prologue_end = std::min (func_end, prev_pc);
+
+  /* Analyze the function prologue.  */
+  csky_analyze_prologue (gdbarch, prologue_start, prologue_end,
+                           func_end, this_frame, cache, lr_type);
+
+  /* gdbarch_sp_regnum contains the value and not the address.  */
+  trad_frame_set_value (cache->saved_regs, sp_regnum, cache->prev_sp);
+  return cache;
+}
+
+/* Implement the unwind_pc gdbarch method.  */
+
+static CORE_ADDR
+csky_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, CSKY_PC_REGNUM);
+}
+
+/* Implement the this_id function for the normal unwinder.  */
+
+static void
+csky_frame_this_id (struct frame_info *this_frame,
+                   void **this_prologue_cache, struct frame_id *this_id)
+{
+  struct csky_unwind_cache *cache;
+  struct frame_id id;
+
+  if (*this_prologue_cache == NULL)
+    *this_prologue_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_prologue_cache;
+
+  /* This marks the outermost frame.  */
+  if (cache->prev_sp == 0)
+    return;
+
+  id = frame_id_build (cache->prev_sp, get_frame_func (this_frame));
+  *this_id = id;
+}
+
+/* Implement the prev_register function for the normal unwinder.  */
+
+static struct value *
+csky_frame_prev_register (struct frame_info *this_frame,
+                         void **this_prologue_cache, int regnum)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_prologue_cache == NULL)
+    *this_prologue_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_prologue_cache;
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+                                      regnum);
+}
+
+/* Data structures for the normal prologue-analysis-based
+   unwinder.  */
+
+static const struct frame_unwind csky_unwind_cache = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  csky_frame_this_id,
+  csky_frame_prev_register,
+  NULL,
+  default_frame_sniffer,
+  NULL,
+  NULL
+};
+
+
+
+static int
+csky_stub_unwind_sniffer (const struct frame_unwind *self,
+                        struct frame_info *this_frame,
+                        void **this_prologue_cache)
+{
+  CORE_ADDR addr_in_block;
+
+  addr_in_block = get_frame_address_in_block (this_frame);
+
+  if (find_pc_partial_function (addr_in_block, NULL, NULL, NULL) == 0
+      || in_plt_section (addr_in_block))
+    return 1;
+
+  return 0;
+}
+
+static struct csky_unwind_cache *
+csky_make_stub_cache (struct frame_info *this_frame)
+{
+  struct csky_unwind_cache *cache;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct csky_unwind_cache);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  cache->prev_sp = get_frame_register_unsigned (this_frame,
CSKY_SP_REGNUM);
+
+  return cache;
+}
+
+static void
+csky_stub_this_id (struct frame_info *this_frame,
+                 void **this_cache,
+                 struct frame_id *this_id)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_make_stub_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  /* Our frame ID for a stub frame is the current SP and LR.  */
+  *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
+}
+
+static struct value *
+csky_stub_prev_register (struct frame_info *this_frame,
+                           void **this_cache,
+                           int prev_regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_make_stub_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  /* If we are asked to unwind the PC, then return the LR.  */
+  if (prev_regnum == CSKY_PC_REGNUM)
+    {
+      CORE_ADDR lr;
+
+      lr = frame_unwind_register_unsigned (this_frame, CSKY_LR_REGNUM);
+      return frame_unwind_got_constant (this_frame, prev_regnum, lr);
+    }
+
+  if (prev_regnum == CSKY_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, prev_regnum,
cache->prev_sp);
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+                                      prev_regnum);
+}
+
+struct frame_unwind csky_stub_unwind = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  csky_stub_this_id,
+  csky_stub_prev_register,
+  NULL,
+  csky_stub_unwind_sniffer
+};
+
+/* Implement the this_base, this_locals, and this_args hooks
+   for the normal unwinder.  */
+
+static CORE_ADDR
+csky_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+  struct csky_unwind_cache *cache;
+
+  if (*this_cache == NULL)
+    *this_cache = csky_frame_unwind_cache (this_frame);
+  cache = (struct csky_unwind_cache *) *this_cache;
+
+  return cache->prev_sp - cache->framesize;
+}
+
+static const struct frame_base csky_frame_base = {
+  &csky_unwind_cache,
+  csky_frame_base_address,
+  csky_frame_base_address,
+  csky_frame_base_address
+};
+
+/* Implement the dummy_id gdbarch method.  The frame ID's base
+   needs to match the TOS value saved by save_dummy_frame_tos,
+   and the PC should match the dummy frame's breakpoint.  */
+
+static struct frame_id
+csky_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  unsigned int sp_regnum = CSKY_SP_REGNUM;
+
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, sp_regnum);
+  return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+/* Initialize register access method.  */
+
+static void
+csky_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+                           struct dwarf2_frame_state_reg *reg,
+                           struct frame_info *this_frame)
+{
+  if (regnum == gdbarch_pc_regnum (gdbarch))
+    reg->how = DWARF2_FRAME_REG_RA;
+  else if (regnum == gdbarch_sp_regnum (gdbarch))
+    reg->how = DWARF2_FRAME_REG_CFA;
+}
+
+/* Create csky register groups.  */
+
+static void
+csky_init_reggroup ()
+{
+  cr_reggroup = reggroup_new ("cr", USER_REGGROUP);
+  fr_reggroup = reggroup_new ("fr", USER_REGGROUP);
+  vr_reggroup = reggroup_new ("vr", USER_REGGROUP);
+  mmu_reggroup = reggroup_new ("mmu", USER_REGGROUP);
+  prof_reggroup = reggroup_new ("profiling", USER_REGGROUP);
+}
+
+/* Add register groups into reggroup list.  */
+
+static void
+csky_add_reggroups (struct gdbarch *gdbarch)
+{
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, cr_reggroup);
+  reggroup_add (gdbarch, fr_reggroup);
+  reggroup_add (gdbarch, vr_reggroup);
+  reggroup_add (gdbarch, mmu_reggroup);
+  reggroup_add (gdbarch, prof_reggroup);
+}
+
+/* Return the groups that a CSKY register can be categorised into.  */
+
+static int
+csky_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+                         struct reggroup *reggroup)
+{
+  int raw_p;
+
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
+    return 0;
+
+  if (reggroup == all_reggroup)
+    return 1;
+
+  raw_p = regnum < gdbarch_num_regs (gdbarch);
+  if (reggroup == save_reggroup || reggroup == restore_reggroup)
+    return raw_p;
+
+  if (((regnum >= CSKY_R0_REGNUM) && (regnum <= CSKY_R0_REGNUM + 31))
+      && (reggroup == general_reggroup))
+    return 1;
+
+  if (((regnum == CSKY_PC_REGNUM)
+       || ((regnum >= CSKY_CR0_REGNUM)
+          && (regnum <= CSKY_CR0_REGNUM + 30)))
+      && (reggroup == cr_reggroup))
+    return 2;
+
+  if ((((regnum >= CSKY_VR0_REGNUM) && (regnum <= CSKY_VR0_REGNUM + 15))
+       || ((regnum >= CSKY_VCR0_REGNUM)
+          && (regnum <= CSKY_VCR0_REGNUM + 2)))
+      && (reggroup == vr_reggroup))
+    return 3;
+
+  if (((regnum >= CSKY_MMU_REGNUM) && (regnum <= CSKY_MMU_REGNUM + 8))
+      && (reggroup == mmu_reggroup))
+    return 4;
+
+  if (((regnum >= CSKY_PROFCR_REGNUM)
+       && (regnum <= CSKY_PROFCR_REGNUM + 48))
+      && (reggroup == prof_reggroup))
+    return 5;
+
+  if ((((regnum >= CSKY_FR0_REGNUM) && (regnum <= CSKY_FR0_REGNUM + 15))
+       || ((regnum >= CSKY_VCR0_REGNUM) && (regnum <= CSKY_VCR0_REGNUM
+ 2)))
+      && (reggroup == fr_reggroup))
+    return 6;
+
+  return 0;
+}
+
+/* Implement the dwarf2_reg_to_regnum gdbarch method.  */
+
+static int
+csky_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int dw_reg)
+{
+  if (dw_reg < 0 || dw_reg >= CSKY_NUM_REGS)
+    return -1;
+  return dw_reg;
+}
+
+/* Override interface for command: info register.  */
+
+static void
+csky_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
+                          struct frame_info *frame, int regnum, int all)
+{
+  /* Call default print_registers_info function.  */
+  default_print_registers_info (gdbarch, file, frame, regnum, all);
+
+  /* For command: info register.  */
+  if (regnum == -1 && all == 0)
+    {
+      default_print_registers_info (gdbarch, file, frame,
+                                   CSKY_PC_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+                                   CSKY_EPC_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+                                   CSKY_CR0_REGNUM, 0);
+      default_print_registers_info (gdbarch, file, frame,
+                                   CSKY_EPSR_REGNUM, 0);
+    }
+  return;
+}
+
+/* Initialize the current architecture based on INFO.  If possible,
+   re-use an architecture from ARCHES, which is a list of
+   architectures already created during this debugging session.
+
+   Called at program startup, when reading a core file, and when
+   reading a binary file.  */
+
+static struct gdbarch *
+csky_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+
+  /* Find a candidate among the list of pre-declared architectures.  */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return arches->gdbarch;
+
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = XCNEW (struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* Target data types.  */
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_addr_bit (gdbarch, 32);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+
+  /* Information about the target architecture.  */
+  set_gdbarch_return_value (gdbarch, csky_return_value);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch,
csky_breakpoint_kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch,
csky_sw_breakpoint_from_kind);
+
+  /* Register architecture.  */
+  set_gdbarch_num_regs (gdbarch, CSKY_NUM_REGS);
+  set_gdbarch_pc_regnum (gdbarch, CSKY_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CSKY_SP_REGNUM);
+  set_gdbarch_register_name (gdbarch, csky_register_name);
+  set_gdbarch_register_type (gdbarch, csky_register_type);
+  set_gdbarch_read_pc (gdbarch, csky_read_pc);
+  set_gdbarch_write_pc (gdbarch, csky_write_pc);
+  set_gdbarch_print_registers_info (gdbarch, csky_print_registers_info);
+  csky_add_reggroups (gdbarch);
+  set_gdbarch_register_reggroup_p (gdbarch, csky_register_reggroup_p);
+  set_gdbarch_stab_reg_to_regnum (gdbarch, csky_dwarf_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, csky_dwarf_reg_to_regnum);
+  dwarf2_frame_set_init_reg (gdbarch, csky_dwarf2_frame_init_reg);
+
+  /* Functions to analyze frames.  */
+  frame_base_set_default (gdbarch, &csky_frame_base);
+  set_gdbarch_skip_prologue (gdbarch, csky_skip_prologue);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_frame_align (gdbarch, csky_frame_align);
+  set_gdbarch_stack_frame_destroyed_p (gdbarch,
csky_stack_frame_destroyed_p);
+
+  /* Functions to access frame data.  */
+  set_gdbarch_unwind_pc (gdbarch, csky_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, csky_unwind_sp);
+
+  /* Functions handling dummy frames.  */
+  set_gdbarch_push_dummy_call (gdbarch, csky_push_dummy_call);
+  set_gdbarch_dummy_id (gdbarch, csky_dummy_id);
+
+  /* Frame unwinders.  Use DWARF debug info if available,
+     otherwise use our own unwinder.  */
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &csky_stub_unwind);
+  frame_unwind_append_unwinder (gdbarch, &csky_unwind_cache);
+
+  /* Breakpoints.  */
+  set_gdbarch_memory_insert_breakpoint (gdbarch,
+                                       csky_memory_insert_breakpoint);
+  set_gdbarch_memory_remove_breakpoint (gdbarch,
+                                       csky_memory_remove_breakpoint);
+
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
+  /* Support simple overlay manager.  */
+  set_gdbarch_overlay_update (gdbarch, simple_overlay_update);
+  set_gdbarch_char_signed (gdbarch, 0);
+  return gdbarch;
+}
+
+void
+_initialize_csky_tdep (void)
+{
+
+  register_gdbarch_init (bfd_arch_csky, csky_gdbarch_init);
+
+  csky_init_reggroup ();
+
+  /* Allow debugging this file's internals.  */
+  add_setshow_boolean_cmd ("csky", class_maintenance, &csky_debug,
+                          _("Set C-Sky debugging."),
+                          _("Show C-Sky debugging."),
+                          _("When on, C-Sky specific debugging is enabled."),
+                          NULL,
+                          NULL,
+                          &setdebuglist, &showdebuglist);
+}
diff --git a/gdb/csky-tdep.h b/gdb/csky-tdep.h
new file mode 100644
index 0000000000..49c29a9e1c
--- /dev/null
+++ b/gdb/csky-tdep.h
@@ -0,0 +1,355 @@
+/* Target-dependent code for the CSKY architecture, for GDB.
+
+   Copyright (C) 2010-2018 Free Software Foundation, 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/>.  */
+
+#ifndef CSKY_TDEP_H
+#define CSKY_TDEP_H
+
+/* How to interpret the contents of the link register.  */
+enum lr_type_t
+{
+  LR_TYPE_R15,
+  LR_TYPE_EPC,
+  LR_TYPE_FPC
+};
+
+/* Target-dependent structure in gdbarch.  */
+struct gdbarch_tdep
+{
+  /* This is Unused.  */
+};
+
+/* Instruction sizes.  */
+enum csky_insn_size_t
+{
+  CSKY_INSN_SIZE16 = 2,
+  CSKY_INSN_SIZE32 = 4
+};
+
+/* CSKY register numbers.  */
+enum csky_regnum
+{
+  CSKY_R0_REGNUM = 0, /* General registers.  */
+  CSKY_R15_REGNUM = 15,
+  CSKY_PC_REGNUM = 72,
+  CSKY_HI_REGNUM = 20,
+  CSKY_LO_REGNUM = 21,
+  CSKY_CR0_REGNUM = 89,
+  CSKY_VBR_REGNUM = CSKY_CR0_REGNUM + 1,
+  CSKY_EPSR_REGNUM = CSKY_CR0_REGNUM + 2,
+  CSKY_FPSR_REGNUM = CSKY_CR0_REGNUM + 3,
+  CSKY_EPC_REGNUM = CSKY_CR0_REGNUM + 4,
+  CSKY_FPC_REGNUM = CSKY_CR0_REGNUM + 5,
+
+  /* Float register 0.  */
+  CSKY_FR0_REGNUM = 40,
+  CSKY_VCR0_REGNUM = 121,
+  CSKY_MMU_REGNUM = 128,
+  CSKY_PROFCR_REGNUM = 140,
+  CSKY_PROFGR_REGNUM = 144,
+  CSKY_FP_REGNUM = 8,
+
+  /* Vector register 0.  */
+  CSKY_VR0_REGNUM = 56,
+
+  /* m32r calling convention.  */
+  CSKY_SP_REGNUM = CSKY_R0_REGNUM + 14,
+  CSKY_RET_REGNUM = CSKY_R0_REGNUM,
+
+  /* Argument registers.  */
+  CSKY_ABI_A0_REGNUM = 0,
+  CSKY_ABI_LAST_ARG_REGNUM = 3,
+
+  /* Link register, r15.  */
+  CSKY_LR_REGNUM = CSKY_R15_REGNUM,
+
+  /* Processor status register, cr0.  */
+  CSKY_PSR_REGNUM = CSKY_CR0_REGNUM,
+
+  CSKY_MAX_REGISTER_SIZE = 16,
+  CSKY_MAX_REGS = 253
+};
+
+/* ICE registers.  */
+#define CSKY_CRBANK_NUM_REGS 32
+
+/* Number of processor registers w/o ICE registers.  */
+#define CSKY_NUM_REGS (CSKY_MAX_REGS - CSKY_CRBANK_NUM_REGS)
+
+/* size.  */
+#define CSKY_16_ST_SIZE(insn) (1 << ((insn & 0x1800) >> 11))
+/* rx.  */
+#define CSKY_16_ST_ADDR_REGNUM(insn) ((insn & 0x700) >> 8)
+/* disp.  */
+#define CSKY_16_ST_OFFSET(insn) ((insn & 0x1f) << ((insn & 0x1800) >> 11))
+/* ry.  */
+#define CSKY_16_ST_VAL_REGNUM(insn) ((insn & 0xe0) >> 5)
+
+/* st16.w rz, (sp, disp).  */
+#define CSKY_16_IS_STWx0(insn) ((insn & 0xf800) == 0xb800)
+#define CSKY_16_STWx0_VAL_REGNUM(insn) CSKY_16_ST_ADDR_REGNUM (insn)
+
+/* disp.  */
+#define CSKY_16_STWx0_OFFSET(insn) \
+  ((((insn & 0x700) >> 3) + (insn & 0x1f)) << 2)
+
+/* Check ld16 but not ld16 sp.  */
+#define CSKY_16_IS_LD(insn) \
+  (((insn & 0xe000) == 0x8000) && (insn & 0x1800) != 0x1800)
+/* size.  */
+#define CSKY_16_LD_SIZE(insn) CSKY_16_ST_SIZE (insn)
+/* rx.  */
+#define CSKY_16_LD_ADDR_REGNUM(insn) CSKY_16_ST_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_16_LD_OFFSET(insn) CSKY_16_ST_OFFSET (insn)
+
+/* ld16.w rz,(sp,disp).  */
+#define CSKY_16_IS_LDWx0(insn) ((insn & 0xf800) == 0x9800)
+/*disp.  */
+#define CSKY_16_LDWx0_OFFSET(insn) CSKY_16_STWx0_OFFSET (insn)
+
+/* st32.b/h/w/d.  */
+#define CSKY_32_IS_ST(insn) ((insn & 0xfc00c000) == 0xdc000000)
+
+/* size: b/h/w/d.  */
+#define CSKY_32_ST_SIZE(insn) (1 << ((insn & 0x3000) >> 12))
+/* rx.  */
+#define CSKY_32_ST_ADDR_REGNUM(insn) ((insn & 0x001f0000) >> 16)
+/* disp.  */
+#define CSKY_32_ST_OFFSET(insn) ((insn & 0xfff) << ((insn & 0x3000) >> 12))
+/* ry.  */
+#define CSKY_32_ST_VAL_REGNUM(insn) ((insn & 0x03e00000) >> 21)
+
+/* stw ry, (sp, disp).  */
+#define CSKY_32_IS_STWx0(insn) ((insn & 0xfc1ff000) == 0xdc0e2000)
+
+/* stm32 ry-rz, (rx).  */
+#define CSKY_32_IS_STM(insn) ((insn & 0xfc00ffe0) == 0xd4001c20)
+/* rx.  */
+#define CSKY_32_STM_ADDR_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* Count of registers.  */
+#define CSKY_32_STM_SIZE(insn) (insn & 0x1f)
+/* ry.  */
+#define CSKY_32_STM_VAL_REGNUM(insn) ((insn & 0x03e00000) >> 21)
+/* stm32 ry-rz, (sp).  */
+#define CSKY_32_IS_STMx0(insn) ((insn & 0xfc1fffe0) == 0xd40e1c20)
+
+/* str32.b/h/w rz, (rx, ry << offset).  */
+#define CSKY_32_IS_STR(insn) \
+  (((insn & 0xfc000000) == 0xd4000000) && !(CSKY_32_IS_STM (insn)))
+/* rx.  */
+#define CSKY_32_STR_X_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* ry.  */
+#define CSKY_32_STR_Y_REGNUM(insn) ((insn >> 21) & 0x1f)
+/* size: b/h/w.  */
+#define CSKY_32_STR_SIZE(insn) (1 << ((insn & 0x0c00) >> 10))
+/* imm (for rx + ry * imm).  */
+#define CSKY_32_STR_OFFSET(insn) ((insn & 0x000003e0) >> 5)
+
+/* stex32.w rz, (rx, disp).  */
+#define CSKY_32_IS_STEX(insn) ((insn & 0xfc00f000) == 0xdc007000)
+/* rx.  */
+#define CSKY_32_STEX_ADDR_REGNUM(insn) ((insn & 0x1f0000) >> 16)
+/* disp.  */
+#define CSKY_32_STEX_OFFSET(insn) ((insn & 0x0fff) << 2)
+
+/* ld.b/h/w.  */
+#define CSKY_32_IS_LD(insn) ((insn & 0xfc00c000) == 0xd8000000)
+/* size.  */
+#define CSKY_32_LD_SIZE(insn) CSKY_32_ST_SIZE (insn)
+/* rx.  */
+#define CSKY_32_LD_ADDR_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_32_LD_OFFSET(insn) CSKY_32_ST_OFFSET (insn)
+#define CSKY_32_IS_LDM(insn) ((insn & 0xfc00ffe0) == 0xd0001c20)
+/* rx.  */
+#define CSKY_32_LDM_ADDR_REGNUM(insn) CSKY_32_STM_ADDR_REGNUM (insn)
+/* Count of registers.  */
+#define CSKY_32_LDM_SIZE(insn) CSKY_32_STM_SIZE (insn)
+
+/* ldr32.b/h/w rz, (rx, ry << offset).  */
+#define CSKY_32_IS_LDR(insn) \
+  (((insn & 0xfc00fe00) == 0xd0000000) && !(CSKY_32_IS_LDM (insn)))
+/* rx.  */
+#define CSKY_32_LDR_X_REGNUM(insn) CSKY_32_STR_X_REGNUM (insn)
+/* ry.  */
+#define CSKY_32_LDR_Y_REGNUM(insn) CSKY_32_STR_Y_REGNUM (insn)
+/* size: b/h/w.  */
+#define CSKY_32_LDR_SIZE(insn) CSKY_32_STR_SIZE (insn)
+/* imm (for rx + ry*imm).  */
+#define CSKY_32_LDR_OFFSET(insn) CSKY_32_STR_OFFSET (insn)
+
+#define CSKY_32_IS_LDEX(insn) ((insn & 0xfc00f000) == 0xd8007000)
+/* rx.  */
+#define CSKY_32_LDEX_ADDR_REGNUM(insn) CSKY_32_STEX_ADDR_REGNUM (insn)
+/* disp.  */
+#define CSKY_32_LDEX_OFFSET(insn) CSKY_32_STEX_OFFSET (insn)
+
+/* subi.sp sp, disp.  */
+#define CSKY_16_IS_SUBI0(insn) ((insn & 0xfce0) == 0x1420)
+/* disp.  */
+#define CSKY_16_SUBI_IMM(insn) ((((insn & 0x300) >> 3) + (insn & 0x1f))
<< 2)
+
+/* subi32 sp,sp,oimm12.  */
+#define CSKY_32_IS_SUBI0(insn) ((insn & 0xfffff000) == 0xe5ce1000)
+/* oimm12.  */
+#define CSKY_32_SUBI_IMM(insn) ((insn & 0xfff) + 1)
+
+/* push16.  */
+#define CSKY_16_IS_PUSH(insn) ((insn & 0xffe0) == 0x14c0)
+#define CSKY_16_IS_PUSH_R15(insn) ((insn & 0x10) == 0x10)
+#define CSKY_16_PUSH_LIST1(insn) (insn & 0xf) /* r4 - r11.  */
+
+/* pop16.  */
+#define CSKY_16_IS_POP(insn) ((insn & 0xffe0) == 0x1480)
+#define CSKY_16_IS_POP_R15(insn) CSKY_16_IS_PUSH_R15 (insn)
+#define CSKY_16_POP_LIST1(insn) CSKY_16_PUSH_LIST1 (insn) /* r4 - r11.  */
+
+/* push32.  */
+#define CSKY_32_IS_PUSH(insn) ((insn & 0xfffffe00) == 0xebe00000)
+#define CSKY_32_IS_PUSH_R29(insn) ((insn & 0x100) == 0x100)
+#define CSKY_32_IS_PUSH_R15(insn) ((insn & 0x10) == 0x10)
+#define CSKY_32_PUSH_LIST1(insn) (insn & 0xf)   /* r4 - r11.  */
+#define CSKY_32_PUSH_LIST2(insn) ((insn & 0xe0) >> 5) /* r16 - r17.  */
+
+/* pop32.  */
+#define CSKY_32_IS_POP(insn) ((insn & 0xfffffe00) == 0xebc00000)
+#define CSKY_32_IS_POP_R29(insn) CSKY_32_IS_PUSH_R29 (insn)
+#define CSKY_32_IS_POP_R15(insn) CSKY_32_IS_PUSH_R15 (insn)
+#define CSKY_32_POP_LIST1(insn) CSKY_32_PUSH_LIST1 (insn) /* r4 - r11.  */
+#define CSKY_32_POP_LIST2(insn) CSKY_32_PUSH_LIST2 (insn) /* r16 - r17.  */
+
+/* Adjust sp by r4(l0).  */
+/* lrw r4, literal.  */
+#define CSKY_16_IS_LRW4(x) (((x) &0xfce0) == 0x1080)
+/* movi r4, imm8.  */
+#define CSKY_16_IS_MOVI4(x) (((x) &0xff00) == 0x3400)
+
+/* addi r4, oimm8.  */
+#define CSKY_16_IS_ADDI4(x) (((x) &0xff00) == 0x2400)
+/* subi r4, oimm8.  */
+#define CSKY_16_IS_SUBI4(x) (((x) &0xff00) == 0x2c00)
+
+/* nor16 r4, r4.  */
+#define CSKY_16_IS_NOR4(x) ((x) == 0x6d12)
+
+/* lsli r4, r4, imm5.  */
+#define CSKY_16_IS_LSLI4(x) (((x) &0xffe0) == 0x4480)
+/* bseti r4, imm5.  */
+#define CSKY_16_IS_BSETI4(x) (((x) &0xffe0) == 0x3ca0)
+/* bclri r4, imm5.  */
+#define CSKY_16_IS_BCLRI4(x) (((x) &0xffe0) == 0x3c80)
+
+/* subu sp, r4.  */
+#define CSKY_16_IS_SUBU4(x) ((x) == 0x6392)
+
+#define CSKY_16_IS_R4_ADJUSTER(x) \
+  (CSKY_16_IS_ADDI4 (x) || CSKY_16_IS_SUBI4 (x) || CSKY_16_IS_BSETI4 (x) \
+   || CSKY_16_IS_BCLRI4 (x) || CSKY_16_IS_NOR4 (x) || CSKY_16_IS_LSLI4 (x))
+
+/* lrw r4, literal.  */
+#define CSKY_32_IS_LRW4(x) (((x) &0xffff0000) == 0xea840000)
+/* movi r4, imm16.  */
+#define CSKY_32_IS_MOVI4(x) (((x) &0xffff0000) == 0xea040000)
+/* movih r4, imm16.  */
+#define CSKY_32_IS_MOVIH4(x) (((x) &0xffff0000) == 0xea240000)
+/* bmaski r4, oimm5.  */
+#define CSKY_32_IS_BMASKI4(x) (((x) &0xfc1fffff) == 0xc4005024)
+/* addi r4, r4, oimm12.  */
+#define CSKY_32_IS_ADDI4(x) (((x) &0xfffff000) == 0xe4840000)
+/* subi r4, r4, oimm12.  */
+#define CSKY_32_IS_SUBI4(x) (((x) &0xfffff000) == 0xe4810000)
+
+/* nor32 r4, r4, r4.  */
+#define CSKY_32_IS_NOR4(x) ((x) == 0xc4842484)
+/* rotli r4, r4, imm5.  */
+#define CSKY_32_IS_ROTLI4(x) (((x) &0xfc1fffff) == 0xc4044904)
+/* lsli r4, r4, imm5.  */
+#define CSKY_32_IS_LISI4(x) (((x) &0xfc1fffff) == 0xc4044824)
+/* bseti32 r4, r4, imm5.  */
+#define CSKY_32_IS_BSETI4(x) (((x) &0xfc1fffff) == 0xc4042844)
+/* bclri32 r4, r4, imm5.  */
+#define CSKY_32_IS_BCLRI4(x) (((x) &0xfc1fffff) == 0xc4042824)
+/* ixh r4, r4, r4.  */
+#define CSKY_32_IS_IXH4(x) ((x) == 0xc4840824)
+/* ixw r4, r4, r4.  */
+#define CSKY_32_IS_IXW4(x) ((x) == 0xc4840844)
+/* subu32 sp, sp, r4.  */
+#define CSKY_32_IS_SUBU4(x) ((x) == 0xc48e008e)
+
+#define CSKY_32_IS_R4_ADJUSTER(x) \
+  (CSKY_32_IS_ADDI4 (x) || CSKY_32_IS_SUBI4 (x) || CSKY_32_IS_ROTLI4 (x) \
+   || CSKY_32_IS_IXH4 (x) || CSKY_32_IS_IXW4 (x) || CSKY_32_IS_NOR4 (x) \
+   || CSKY_32_IS_BSETI4 (x) || CSKY_32_IS_BCLRI4 (x) ||
CSKY_32_IS_LISI4 (x))
+
+#define CSKY_IS_R4_ADJUSTER(x)                                         \
+  (CSKY_32_IS_R4_ADJUSTER (x) || CSKY_16_IS_R4_ADJUSTER (x))
+#define CSKY_IS_SUBU4(x) (CSKY_32_IS_SUBU4 (x) || CSKY_16_IS_SUBU4 (x))
+
+/* mfcr rz, epsr.  */
+#define CSKY_32_IS_MFCR_EPSR(insn) ((insn & 0xffffffe0) == 0xc0026020)
+/* mfcr rz, fpsr.  */
+#define CSKY_32_IS_MFCR_FPSR(insn) ((insn & 0xffffffe0) == 0xc0036020)
+/* mfcr rz, epc.  */
+#define CSKY_32_IS_MFCR_EPC(insn) ((insn & 0xffffffe0) == 0xc0046020)
+/* mfcr rz, fpc.  */
+#define CSKY_32_IS_MFCR_FPC(insn) ((insn & 0xffffffe0) == 0xc0056020)
+
+#define CSKY_32_IS_RTE(insn) (insn == 0xc0004020)
+#define CSKY_32_IS_RFI(insn) (insn == 0xc0004420)
+#define CSKY_32_IS_JMP(insn) ((insn & 0xffe0ffff) == 0xe8c00000)
+#define CSKY_16_IS_JMP(insn) ((insn & 0xffc3) == 0x7800)
+#define CSKY_32_IS_JMPI(insn) ((insn & 0xffff0000) == 0xeac00000)
+#define CSKY_32_IS_JMPIX(insn) ((insn & 0xffe0fffc) == 0xe9e00000)
+#define CSKY_16_IS_JMPIX(insn) ((insn & 0xf8fc) == 0x38e0)
+
+#define CSKY_16_IS_BR(insn) ((insn & 0xfc00) == 0x0400)
+#define CSKY_32_IS_BR(insn) ((insn & 0xffff0000) == 0xe8000000)
+#define CSKY_16_IS_MOV_FP_SP(insn) (insn == 0x6e3b)     /* mov r8, r14.  */
+#define CSKY_32_IS_MOV_FP_SP(insn) (insn == 0xc40e4828) /* mov r8, r14.  */
+#define CSKY_16_IS_MOV_SP_FP(insn) (insn == 0x6fa3)     /* mov r14, r8.  */
+#define CSKY_32_INSN_MASK 0xc000
+#define CSKY_BKPT_INSN 0x0
+#define CSKY_NUM_GREGS 32
+/* 32 general regs + 4.  */
+#define CSKY_NUM_GREGS_SAVED_GREGS (CSKY_NUM_GREGS + 4)
+
+/* CSKY software bkpt write-mode.  */
+#define CSKY_WR_BKPT_MODE 4
+
+/* Define insns for parse rt_sigframe.  */
+/* There are three words(sig, pinfo, puc) before siginfo.  */
+#define CSKY_SIGINFO_OFFSET 0xc
+
+/* Size of struct siginfo.  */
+#define CSKY_SIGINFO_SIZE 0x80
+
+/* There are five words(uc_flags, uc_link, and three for uc_stack)
+   in struct ucontext before sigcontext.  */
+#define CSKY_UCONTEXT_SIGCONTEXT 0x14
+
+/* There is a word(sc_mask) before sc_usp.  */
+#define CSKY_SIGCONTEXT_SC_USP 0x4
+
+/* There is a word(sc_usp) before sc_a0.  */
+#define CSKY_SIGCONTEXT_SC_A0 0x4
+
+#define CSKY_MOVI_R7_173 0x00adea07
+#define CSKY_TRAP_0 0x2020c000
+
+#endif
--
2.11.0


Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Hafiz Abid Qadeer
Polite ping.

Tom Tromey said off-list that he is too ill to review the patch. So some
other maintainer may have to pick it.

The binutils and gcc ports of csky have now been approved and committed.

On 17/08/18 10:18, Abid, Hafiz wrote:

> Polite ping.
> ________________________________________
> From: Hafiz Abid Qadeer <[hidden email]>
> Sent: Saturday, July 28, 2018 12:12 AM
> To: Tom Tromey
> Cc: [hidden email]; [hidden email]; [hidden email]
> Subject: Re: [1/2] C-SKY Port
>
> Hi Tom,
> Thanks for the review. Please see comments and updated patch below
>
> On 27/07/18 16:49, Tom Tromey wrote:
>>>>>>> ">" == Hafiz Abid Qadeer <[hidden email]> writes:
>>
>>>> Add support for new target 'csky'.
>>
>>>> 2018-07-25  Jiangshuai Li  <[hidden email]>
>>>>         Hafiz Abid Qadeer  <[hidden email]>
>>>>         Don Breazeal  <[hidden email]>
>>
>> I didn't check the copyright assignment situation, but for a patch of
>> this size, assignments are needed.  I assume codesourcery has some kind
>> of blanket assignment, but what about Jiangshuai Li?
> Yes, csky aslo have a copyright assignment.
>
>>
>>>> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
>>
>>>> +csky*-linux*)
> Done.
>
>>
>>>> +csky*-*)
> Done.
>
>>
>> It's more normal to mention all the "-"s, so "csky*-*-linux*" and "csky*-*-*".
>>
>> I don't know anything about C-SKY, so I didn't really look deeply at the
>> arch-specific bits.  I assume those pass your testing.
>>
>>>> diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
>>
>>>> +struct stack_item
>>>> +{
>>>> +  int len;
>>>> +  struct stack_item *prev;
>>>> +  void *data;
>>
>> Seems to me that this could be gdb_byte instead of void here, and in
>> push_stack_item and pop_stack_item.
> Done
>
>>
>>>> +/* Implement the push_dummy_call gdbarch method.  */
>>>> +
>>>> +static CORE_ADDR
>>>> +csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
>>>> +                 struct regcache *regcache, CORE_ADDR bp_addr,
>>>> +                 int nargs, struct value **args, CORE_ADDR sp,
>>>> +                 int struct_return, CORE_ADDR struct_addr)
>>>> +{
>> [...]
>>>> +      arg_type = check_typedef (value_type (args[argnum]));
>>>> +      len = TYPE_LENGTH (arg_type);
>>>> +      val = value_contents (args[argnum]);
>>
>> I wonder if this can ever throw.
>>
>> In theory of course it can.  But maybe in practice it isn't possible?
>> I don't know.
>>
>> The issue is, if it can throw, then the stack_items will be leaked.
>> A way around that is to redo the stack as self-managing C++ objects and
>> use a local std::vector or the like to hold them.
>>
>>>> +  /* Transfer the dummy stack frame to the target.  */
>>>> +  while (si)
>>>> +    {
>>>> +      sp -= si->len;
>>>> +      write_memory (sp, (const bfd_byte *) si->data, si->len);
>>
>> A similar consideration applies here.
> I removed the push/pull_stack_item and instead introduced a vector as
> you suggested.
>>
>>
>> This all seems pretty reasonable to me.
> If it is approved, is there any chance that patch can make it to 8.2
> release?
>
> Thanks,
> Abid
>
>
>
> --
> 2018-07-27  Jiangshuai Li  <[hidden email]>
>             Hafiz Abid Qadeer  <[hidden email]>
>             Don Breazeal  <[hidden email]>
>
>         * csky-linux-tdep.c: New file.
>         * csky-tdep.c: Likewise.
>         * csky-tdep.h: Likewise.
>         * Makefile.in (ALL_TARGET_OBS): Add csky-linux-tdep.o and
>         csky-tdep.o.
>         (HFILES_NO_SRCDIR): Add csky-tdep.h.
>         (ALLDEPFILES): Add csky-linux-tdep.c and csky-tdep.c
>         * configure.tgt: Add csky support.
> ---
>  gdb/Makefile.in       |    5 +
>  gdb/configure.tgt     |   11 +
>  gdb/csky-linux-tdep.c |  263 ++++++
>  gdb/csky-tdep.c       | 2307
> +++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/csky-tdep.h       |  355 ++++++++
>  5 files changed, 2941 insertions(+)
>  create mode 100644 gdb/csky-linux-tdep.c
>  create mode 100644 gdb/csky-tdep.c
>  create mode 100644 gdb/csky-tdep.h
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 8c744d70c0..9eb420f250 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -688,6 +688,8 @@ ALL_TARGET_OBS = \
>         bsd-uthread.o \
>         cris-linux-tdep.o \
>         cris-tdep.o \
> +       csky-linux-tdep.o \
> +       csky-tdep.o \
>         dicos-tdep.o \
>         fbsd-tdep.o \
>         frv-linux-tdep.o \
> @@ -1207,6 +1209,7 @@ HFILES_NO_SRCDIR = \
>         completer.h \
>         cp-abi.h \
>         cp-support.h \
> +       csky-tdep.h \
>         ctf.h \
>         d-lang.h \
>         darwin-nat.h \
> @@ -2207,6 +2210,8 @@ ALLDEPFILES = \
>         bfin-tdep.c \
>         bsd-kvm.c \
>         bsd-uthread.c \
> +       csky-linux-tdep.c \
> +       csky-tdep.c \
>         darwin-nat.c \
>         dicos-tdep.c \
>         fbsd-nat.c \
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index f197160896..d2cd20dbcd 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -206,6 +206,17 @@ cris*)
>         gdb_target_obs="cris-tdep.o cris-linux-tdep.o linux-tdep.o solib-svr4.o"
>         ;;
>
> +csky*-*-linux*)
> +       # Target: CSKY running GNU/Linux
> +       gdb_target_obs="csky-tdep.o csky-linux-tdep.o glibc-tdep.o \
> +                       linux-tdep.o solib-svr4.o"
> +       ;;
> +
> +csky*-*-*)
> +       # Target: CSKY bare metal
> +       gdb_target_obs="csky-tdep.o"
> +       ;;
> +
>  frv-*-*)
>         # Target: Fujitsu FRV processor
>         gdb_target_obs="frv-tdep.o frv-linux-tdep.o linux-tdep.o solib-frv.o"
> diff --git a/gdb/csky-linux-tdep.c b/gdb/csky-linux-tdep.c
> new file mode 100644
> index 0000000000..9e3ec393c8
> --- /dev/null
> +++ b/gdb/csky-linux-tdep.c
> @@ -0,0 +1,263 @@
> +/* Target-dependent code for GNU/Linux on CSKY.
> +
> +   Copyright (C) 2012-2018 Free Software Foundation, Inc.
> +
> +   Contributed by C-SKY Microsystems and Mentor Graphics.
> +
> +   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 "osabi.h"
> +#include "glibc-tdep.h"
> +#include "linux-tdep.h"
> +#include "gdbarch.h"
> +#include "solib-svr4.h"
> +#include "regset.h"
> +#include "trad-frame.h"
> +#include "tramp-frame.h"
> +#include "csky-tdep.h"
> +
> +/* Functions, definitions, and data structures for C-Sky core file
> debug.  */
> +
> +/* General regset pc, r1, r0, psr, r2-r31 for CK810.  */
> +#define SIZEOF_CSKY_GREGSET 34*4
> +/* Float regset fesr fsr fr0-fr31 for CK810.  */
> +#define SIZEOF_CSKY_FREGSET 34*4
> +
> +/* Offset mapping table from core_section to regcache of general
> +   registers for ck810.  */
> +static const int csky_gregset_offset[] =
> +{
> +  72,  1,  0, 89,  2,  /* pc, r1, r0, psr, r2.  */
> +   3,  4,  5,  6,  7,  /* r3 ~ r32.  */
> +   8,  9, 10, 11, 12,
> +  13, 14, 15, 16, 17,
> +  18, 19, 20, 21, 22,
> +  23, 24, 25, 26, 27,
> +  28, 29, 30, 31
> +};
> +
> +/* Offset mapping table from core_section to regcache of float
> +   registers for ck810.  */
> +
> +static const int csky_fregset_offset[] =
> +{
> +  122, 123, 40, 41, 42,     /* fcr, fesr, fr0 ~ fr2.  */
> +   43,  44, 45, 46, 47,     /* fr3 ~ fr15.  */
> +   48,  49, 50, 51, 52,
> +   53,  54, 55
> +};
> +
> +/* Implement the supply_regset hook for GP registers in core files.  */
> +
> +static void
> +csky_supply_gregset (const struct regset *regset,
> +                    struct regcache *regcache, int regnum,
> +                    const void *regs, size_t len)
> +{
> +  int i, gregset_num;
> +  const gdb_byte *gregs = (const gdb_byte *) regs ;
> +
> +  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
> +  gregset_num = ARRAY_SIZE (csky_gregset_offset);
> +
> +  for (i = 0; i < gregset_num; i++)
> +    {
> +      if ((regnum == csky_gregset_offset[i] || regnum == -1)
> +         && csky_gregset_offset[i] != -1)
> +       regcache->raw_supply (csky_gregset_offset[i], gregs + 4 * i);
> +    }
> +}
> +
> +/* Implement the collect_regset hook for GP registers in core files.  */
> +
> +static void
> +csky_collect_gregset (const struct regset *regset,
> +                     const struct regcache *regcache,
> +                     int regnum, void *gregs_buf, size_t len)
> +{
> +  int regno, gregset_num;
> +  gdb_byte *gregs = (gdb_byte *) gregs_buf ;
> +
> +  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
> +  gregset_num = ARRAY_SIZE (csky_gregset_offset);
> +
> +  for (regno = 0; regno < gregset_num; regno++)
> +    {
> +      if ((regnum == csky_gregset_offset[regno] || regnum == -1)
> +         && csky_gregset_offset[regno] != -1)
> +       regcache->raw_collect (regno,
> +                              gregs + 4 + csky_gregset_offset[regno]);
> +    }
> +}
> +
> +/* Implement the supply_regset hook for FP registers in core files.  */
> +
> +void
> +csky_supply_fregset (const struct regset *regset,
> +                    struct regcache *regcache, int regnum,
> +                    const void *regs, size_t len)
> +{
> +  int i;
> +  int offset = 0;
> +  struct gdbarch *gdbarch = regcache->arch ();
> +  const gdb_byte *fregs = (const gdb_byte *) regs;
> +  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
> +
> +  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
> +  for (i = 0; i < fregset_num; i++)
> +    {
> +      if ((regnum == csky_fregset_offset[i] || regnum == -1)
> +         && csky_fregset_offset[i] != -1)
> +       {
> +         int num = csky_fregset_offset[i];
> +         offset += register_size (gdbarch, num);
> +         regcache->raw_supply (csky_fregset_offset[i], fregs + offset);
> +       }
> +    }
> +}
> +
> +/* Implement the collect_regset hook for FP registers in core files.  */
> +
> +static void
> +csky_collect_fregset (const struct regset *regset,
> +                     const struct regcache *regcache,
> +                     int regnum, void *fregs_buf, size_t len)
> +{
> +  int regno;
> +  struct gdbarch *gdbarch = regcache->arch ();
> +  gdb_byte *fregs = (gdb_byte *) fregs_buf ;
> +  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
> +  int offset = 0;
> +
> +  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
> +  for (regno = 0; regno < fregset_num; regno++)
> +    {
> +      if ((regnum == csky_fregset_offset[regno] || regnum == -1)
> +         && csky_fregset_offset[regno] != -1)
> +       {
> +         offset += register_size (gdbarch, csky_fregset_offset[regno]);
> +         regcache->raw_collect (regno, fregs + offset);
> +       }
> +    }
> +}
> +
> +static const struct regset csky_regset_general =
> +{
> +  NULL,
> +  csky_supply_gregset,
> +  csky_collect_gregset
> +};
> +
> +static const struct regset csky_regset_float =
> +{
> +  NULL,
> +  csky_supply_fregset,
> +  csky_collect_fregset
> +};
> +
> +/* Iterate over core file register note sections.  */
> +
> +static void
> +csky_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
> +                                        iterate_over_regset_sections_cb *cb,
> +                                        void *cb_data,
> +                                        const struct regcache *regcache)
> +{
> +  cb (".reg", sizeof (csky_gregset_offset), &csky_regset_general,
> +      NULL, cb_data);
> +  cb (".reg2", sizeof (csky_fregset_offset), &csky_regset_float,
> +      NULL, cb_data);
> +}
> +
> +static void
> +csky_linux_rt_sigreturn_init (const struct tramp_frame *self,
> +                             struct frame_info *this_frame,
> +                             struct trad_frame_cache *this_cache,
> +                             CORE_ADDR func)
> +{
> +  int i;
> +  CORE_ADDR sp = get_frame_register_unsigned (this_frame, 14);
> +
> +  CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE
> +                  + CSKY_UCONTEXT_SIGCONTEXT
> +                  + CSKY_SIGCONTEXT_SC_USP
> +                  + CSKY_SIGCONTEXT_SC_A0;
> +
> +  /* Set addrs of R0 ~ R13.  */
> +  for (i = 0; i < 14; i++)
> +   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
> +
> +  /* Set addrs of SP(R14) and R15.  */
> +  trad_frame_set_reg_addr (this_cache, 14, base - 4);
> +  trad_frame_set_reg_addr (this_cache, 15, base + 4 * 14);
> +
> +  /* Set addrs of R16 ~ R31.  */
> +  for (i = 15; i < 31; i++)
> +   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
> +
> +  /* Set addrs of PSR and PC.  */
> +  trad_frame_set_reg_addr (this_cache, 89, base + 4 * 33);
> +  trad_frame_set_reg_addr (this_cache, 72, base + 4 * 34);
> +
> +  trad_frame_set_id (this_cache, frame_id_build (sp, func));
> +}
> +
> +static struct tramp_frame
> +csky_linux_rt_sigreturn_tramp_frame = {
> +  SIGTRAMP_FRAME,
> +  4,
> +  {
> +    { CSKY_MOVI_R7_173, -1 },
> +    { CSKY_TRAP_0, -1 },
> +    { TRAMP_SENTINEL_INSN }
> +  },
> +  csky_linux_rt_sigreturn_init
> +};
> +
> +/* Hook function for gdbarch_register_osabi.  */
> +
> +static void
> +csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  linux_init_abi (info, gdbarch);
> +
> +  /* Shared library handling.  */
> +  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
> +  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
> +  set_solib_svr4_fetch_link_map_offsets (gdbarch,
> +                                        svr4_ilp32_fetch_link_map_offsets);
> +
> +  /* Enable TLS support.  */
> +  set_gdbarch_fetch_tls_load_module_address (gdbarch,
> +                                            svr4_fetch_objfile_link_map);
> +
> +  /* Core file support.  */
> +  set_gdbarch_iterate_over_regset_sections (
> +    gdbarch, csky_linux_iterate_over_regset_sections);
> +
> +  /* Append tramp frame unwinder for SIGNAL.  */
> +
> +  tramp_frame_prepend_unwinder (gdbarch,
> +                               &csky_linux_rt_sigreturn_tramp_frame);
> +}
> +
> +void
> +_initialize_csky_linux_tdep (void)
> +{
> +  gdbarch_register_osabi (bfd_arch_csky, 0, GDB_OSABI_LINUX,
> +                         csky_linux_init_abi);
> +}
> diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
> new file mode 100644
> index 0000000000..4ddadc7885
> --- /dev/null
> +++ b/gdb/csky-tdep.c
> @@ -0,0 +1,2307 @@
> +/* Target-dependent code for the CSKY architecture, for GDB.
> +
> +   Copyright (C) 2010-2018 Free Software Foundation, Inc.
> +
> +   Contributed by C-SKY Microsystems and Mentor Graphics.
> +
> +   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 "gdb_assert.h"
> +#include "frame.h"
> +#include "inferior.h"
> +#include "symtab.h"
> +#include "value.h"
> +#include "gdbcmd.h"
> +#include "language.h"
> +#include "gdbcore.h"
> +#include "symfile.h"
> +#include "objfiles.h"
> +#include "gdbtypes.h"
> +#include "target.h"
> +#include "arch-utils.h"
> +#include "regcache.h"
> +#include "osabi.h"
> +#include "block.h"
> +#include "reggroups.h"
> +#include "elf/csky.h"
> +#include "elf-bfd.h"
> +#include "symcat.h"
> +#include "sim-regno.h"
> +#include "dis-asm.h"
> +#include "frame-unwind.h"
> +#include "frame-base.h"
> +#include "trad-frame.h"
> +#include "infcall.h"
> +#include "floatformat.h"
> +#include "remote.h"
> +#include "target-descriptions.h"
> +#include "dwarf2-frame.h"
> +#include "user-regs.h"
> +#include "valprint.h"
> +#include "reggroups.h"
> +#include "csky-tdep.h"
> +#include "regset.h"
> +#include "block.h"
> +#include "opcode/csky.h"
> +#include <algorithm>
> +#include <vector>
> +
> +/* Control debugging information emitted in this file.  */
> +static int csky_debug = 0;
> +
> +static struct reggroup *cr_reggroup;
> +static struct reggroup *fr_reggroup;
> +static struct reggroup *vr_reggroup;
> +static struct reggroup *mmu_reggroup;
> +static struct reggroup *prof_reggroup;
> +
> +/* Convenience function to print debug messages in prologue analysis.  */
> +
> +static void
> +print_savedreg_msg (int regno, int offsets[], bool print_continuing)
> +{
> +  fprintf_unfiltered (gdb_stdlog, "csky: r%d saved at offset 0x%x\n",
> +                     regno, offsets[regno]);
> +  if (print_continuing)
> +    fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
> +}
> +
> +/*  Check whether the instruction at ADDR is 16-bit or not.  */
> +
> +static int
> +csky_pc_is_csky16 (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  gdb_byte target_mem[2];
> +  int status;
> +  unsigned int insn;
> +  int ret = 1;
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +
> +  status = target_read_memory (addr, target_mem, 2);
> +  /* Assume a 16-bit instruction if we can't read memory.  */
> +  if (status)
> +    return 1;
> +
> +  /* Get instruction from memory.  */
> +  insn = extract_unsigned_integer (target_mem, 2, byte_order);
> +  if ((insn & CSKY_32_INSN_MASK) == CSKY_32_INSN_MASK)
> +    ret = 0;
> +  else if (insn == CSKY_BKPT_INSN)
> +    {
> +      /* Check for 32-bit bkpt instruction which is all 0.  */
> +      status = target_read_memory (addr + 2, target_mem, 2);
> +      if (status)
> +       return 1;
> +
> +      insn = extract_unsigned_integer (target_mem, 2, byte_order);
> +      if (insn == CSKY_BKPT_INSN)
> +       ret = 0;
> +    }
> +  return ret;
> +}
> +
> +/* Get one instruction at ADDR and store it in INSN.  Return 2 for
> +   a 16-bit instruction or 4 for a 32-bit instruction.  */
> +
> +static int
> +csky_get_insn (struct gdbarch *gdbarch, CORE_ADDR addr, unsigned int *insn)
> +{
> +  gdb_byte target_mem[2];
> +  unsigned int insn_type;
> +  int status;
> +  int insn_len = 2;
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +
> +  status = target_read_memory (addr, target_mem, 2);
> +  if (status)
> +    memory_error (TARGET_XFER_E_IO, addr);
> +
> +  insn_type = extract_unsigned_integer (target_mem, 2, byte_order);
> +  if (CSKY_32_INSN_MASK == (insn_type & CSKY_32_INSN_MASK))
> +    {
> +      status = target_read_memory (addr + 2, target_mem, 2);
> +      if (status)
> +       memory_error (TARGET_XFER_E_IO, addr);
> +      insn_type = ((insn_type << 16)
> +                  | extract_unsigned_integer (target_mem, 2, byte_order));
> +      insn_len = 4;
> +    }
> +  *insn = insn_type;
> +  return insn_len;
> +}
> +
> +/* Implement the read_pc gdbarch method.  */
> +
> +static CORE_ADDR
> +csky_read_pc (readable_regcache *regcache)
> +{
> +  ULONGEST pc;
> +  regcache->cooked_read (CSKY_PC_REGNUM, &pc);
> +  return pc;
> +}
> +
> +/* Implement the write_pc gdbarch method.  */
> +
> +static void
> +csky_write_pc (regcache *regcache, CORE_ADDR val)
> +{
> +  regcache_cooked_write_unsigned (regcache, CSKY_PC_REGNUM, val);
> +}
> +
> +/* Implement the unwind_sp gdbarch method.  */
> +
> +static CORE_ADDR
> +csky_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
> +{
> +  return frame_unwind_register_unsigned (next_frame, CSKY_SP_REGNUM);
> +}
> +
> +/* C-Sky ABI register names.  */
> +
> +static const char *csky_register_names[] =
> +{
> +  /* General registers 0 - 31.  */
> +  "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
> +  "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
> +  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
> +  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
> +
> +  /* DSP hilo registers 36 and 37.  */
> +  "",      "",    "",     "",     "hi",    "lo",   "",    "",
> +
> +  /* FPU/VPU general registers 40 - 71.  */
> +  "fr0", "fr1", "fr2",  "fr3",  "fr4",  "fr5",  "fr6",  "fr7",
> +  "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
> +  "vr0", "vr1", "vr2",  "vr3",  "vr4",  "vr5",  "vr6",  "vr7",
> +  "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15",
> +
> +  /* Program counter 72.  */
> +  "pc",
> +
> +  /* Optional registers (ar) 73 - 88.  */
> +  "ar0", "ar1", "ar2",  "ar3",  "ar4",  "ar5",  "ar6",  "ar7",
> +  "ar8", "ar9", "ar10", "ar11", "ar12", "ar13", "ar14", "ar15",
> +
> +  /* Control registers (cr) 89 - 119.  */
> +  "psr",  "vbr",  "epsr", "fpsr", "epc",  "fpc",  "ss0",  "ss1",
> +  "ss2",  "ss3",  "ss4",  "gcr",  "gsr",  "cr13", "cr14", "cr15",
> +  "cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
> +  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
> +
> +  /* FPU/VPU control registers 121 ~ 123.  */
> +  /* User sp 127.  */
> +  "fid", "fcr", "fesr", "", "", "", "usp",
> +
> +  /* MMU control registers: 128 - 136.  */
> +  "mcr0", "mcr2", "mcr3", "mcr4", "mcr6", "mcr8", "mcr29", "mcr30",
> +  "mcr31", "", "", "",
> +
> +  /* Profiling control registers 140 - 143.  */
> +  /* Profiling software general registers 144 - 157.  */
> +  "profcr0",  "profcr1",  "profcr2",  "profcr3",  "profsgr0",  "profsgr1",
> +  "profsgr2", "profsgr3", "profsgr4", "profsgr5", "profsgr6",  "profsgr7",
> +  "profsgr8", "profsgr9", "profsgr10","profsgr11","profsgr12", "profsgr13",
> +  "",   "",
> +
> +  /* Profiling architecture general registers 160 - 174.  */
> +  "profagr0", "profagr1", "profagr2", "profagr3", "profagr4", "profagr5",
> +  "profagr6", "profagr7", "profagr8", "profagr9", "profagr10","profagr11",
> +  "profagr12","profagr13","profagr14", "",
> +
> +  /* Profiling extension general registers 176 - 188.  */
> +  "profxgr0", "profxgr1", "profxgr2", "profxgr3", "profxgr4", "profxgr5",
> +  "profxgr6", "profxgr7", "profxgr8", "profxgr9", "profxgr10","profxgr11",
> +  "profxgr12",
> +
> +  /* Control registers in bank1.  */
> +  "", "", "", "", "", "", "", "",
> +  "", "", "", "", "", "", "", "",
> +  "cp1cr16", "cp1cr17", "cp1cr18", "cp1cr19", "cp1cr20", "", "", "",
> +  "", "", "", "", "", "", "", "",
> +
> +  /* Control registers in bank3 (ICE).  */
> +  "sepsr", "sevbr", "seepsr", "", "seepc", "", "nsssp", "seusp",
> +  "sedcr", "", "", "", "", "", "", "",
> +  "", "", "", "", "", "", "", "",
> +  "", "", "", "", "", "", "", ""
> +};
> +
> +/* Implement the register_name gdbarch method.  */
> +
> +static const char *
> +csky_register_name (struct gdbarch *gdbarch, int reg_nr)
> +{
> +  int csky_total_regnum;
> +
> +  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
> +    return tdesc_register_name (gdbarch, reg_nr);
> +
> +  if (reg_nr < 0)
> +    return NULL;
> +
> +  if (reg_nr >= gdbarch_num_regs (gdbarch))
> +    return NULL;
> +
> +  return csky_register_names[reg_nr];
> +}
> +
> +/* Construct vector type for vrx registers.  */
> +
> +static struct type *
> +csky_vector_type (struct gdbarch *gdbarch)
> +{
> +  const struct builtin_type *bt = builtin_type (gdbarch);
> +
> +  struct type *t;
> +
> +  t = arch_composite_type (gdbarch, "__gdb_builtin_type_vec128i",
> +                          TYPE_CODE_UNION);
> +
> +  append_composite_type_field (t, "u32",
> +                              init_vector_type (bt->builtin_int32, 4));
> +  append_composite_type_field (t, "u16",
> +                              init_vector_type (bt->builtin_int16, 8));
> +  append_composite_type_field (t, "u8",
> +                              init_vector_type (bt->builtin_int8, 16));
> +
> +  TYPE_VECTOR (t) = 1;
> +  TYPE_NAME (t) = "builtin_type_vec128i";
> +
> +  return t;
> +}
> +
> +/* Return the GDB type object for the "standard" data type
> +   of data in register N.  */
> +
> +static struct type *
> +csky_register_type (struct gdbarch *gdbarch, int reg_nr)
> +{
> +  int num_regs = gdbarch_num_regs (gdbarch);
> +  int num_pseudo_regs = gdbarch_num_pseudo_regs (gdbarch);
> +
> +  /* PC, EPC, FPC is a text pointer.  */
> +  if ((reg_nr == CSKY_PC_REGNUM)  || (reg_nr == CSKY_EPC_REGNUM)
> +      || (reg_nr == CSKY_FPC_REGNUM))
> +    return builtin_type (gdbarch)->builtin_func_ptr;
> +
> +  /* VBR is a data pointer.  */
> +  if (reg_nr == CSKY_VBR_REGNUM)
> +    return builtin_type (gdbarch)->builtin_data_ptr;
> +
> +  /* Float register has 64 bits, and only in ck810.  */
> +  if ((reg_nr >=CSKY_FR0_REGNUM) && (reg_nr <= CSKY_FR0_REGNUM + 15))
> +      return arch_float_type (gdbarch, 64, "builtin_type_csky_ext",
> +                             floatformats_ieee_double);
> +
> +  /* Vector register has 128 bits, and only in ck810.  */
> +  if ((reg_nr >= CSKY_VR0_REGNUM) && (reg_nr <= CSKY_VR0_REGNUM + 15))
> +    return csky_vector_type (gdbarch);
> +
> +  /* Profiling general register has 48 bits, we use 64bit.  */
> +  if ((reg_nr >= CSKY_PROFGR_REGNUM) && (reg_nr <= CSKY_PROFGR_REGNUM +
> 44))
> +    return builtin_type (gdbarch)->builtin_uint64;
> +
> +  if (reg_nr == CSKY_SP_REGNUM)
> +    return builtin_type (gdbarch)->builtin_data_ptr;
> +
> +  /* Others are 32 bits.  */
> +  return builtin_type (gdbarch)->builtin_int32;
> +}
> +
> +/* Data structure to marshall items in a dummy stack frame when
> +   calling a function in the inferior.  */
> +
> +struct stack_item
> +{
> +  stack_item (int len_, const gdb_byte *data_)
> +  : len (len_), data (data_)
> +  {}
> +
> +  int len;
> +  const gdb_byte *data;
> +};
> +
> +/* Implement the push_dummy_call gdbarch method.  */
> +
> +static CORE_ADDR
> +csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
> +                     struct regcache *regcache, CORE_ADDR bp_addr,
> +                     int nargs, struct value **args, CORE_ADDR sp,
> +                     int struct_return, CORE_ADDR struct_addr)
> +{
> +  int argnum;
> +  int argreg = CSKY_ABI_A0_REGNUM;
> +  int last_arg_regnum = CSKY_ABI_LAST_ARG_REGNUM;
> +  int need_dummy_stack = 0;
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  std::vector<stack_item> stack_items;
> +
> +  /* Set the return address.  For CSKY, the return breakpoint is
> +     always at BP_ADDR.  */
> +  regcache_cooked_write_unsigned (regcache, CSKY_LR_REGNUM, bp_addr);
> +
> +  /* The struct_return pointer occupies the first parameter
> +     passing register.  */
> +  if (struct_return)
> +    {
> +      if (csky_debug)
> +       {
> +         fprintf_unfiltered (gdb_stdlog,
> +                             "csky: struct return in %s = %s\n",
> +                             gdbarch_register_name (gdbarch, argreg),
> +                             paddress (gdbarch, struct_addr));
> +       }
> +      regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
> +      argreg++;
> +    }
> +
> +  /* Put parameters into argument registers in REGCACHE.
> +     In ABI argument registers are r0 through r3.  */
> +  for (argnum = 0; argnum < nargs; argnum++)
> +    {
> +      int len;
> +      struct type *arg_type;
> +      const gdb_byte *val;
> +
> +      arg_type = check_typedef (value_type (args[argnum]));
> +      len = TYPE_LENGTH (arg_type);
> +      val = value_contents (args[argnum]);
> +
> +      /* Copy the argument to argument registers or the dummy stack.
> +        Large arguments are split between registers and stack.
> +
> +        If len < 4, there is no need to worry about endianness since
> +        the arguments will always be stored in the low address.  */
> +      if (len < 4)
> +       {
> +         CORE_ADDR regval
> +           = extract_unsigned_integer (val, len, byte_order);
> +         regcache_cooked_write_unsigned (regcache, argreg, regval);
> +         argreg++;
> +       }
> +      else
> +       {
> +         while (len > 0)
> +           {
> +             int partial_len = len < 4 ? len : 4;
> +             if (argreg <= last_arg_regnum)
> +               {
> +                 /* The argument is passed in an argument register.  */
> +                 CORE_ADDR regval
> +                   = extract_unsigned_integer (val, partial_len,
> +                                               byte_order);
> +                 if (byte_order == BFD_ENDIAN_BIG)
> +                   regval <<= (4 - partial_len) * 8;
> +
> +                 /* Put regval into register in REGCACHE.  */
> +                 regcache_cooked_write_unsigned (regcache, argreg,
> +                                                 regval);
> +                 argreg++;
> +               }
> +             else
> +               {
> +                 /* The argument should be pushed onto the dummy stack.  */
> +                 stack_items.emplace_back (4, val);
> +                 need_dummy_stack += 4;
> +               }
> +             len -= partial_len;
> +             val += partial_len;
> +           }
> +       }
> +    }
> +
> +  /* Transfer the dummy stack frame to the target.  */
> +  std::vector<stack_item>::reverse_iterator iter;
> +  for (iter = stack_items.rbegin (); iter != stack_items.rend (); ++iter)
> +    {
> +      sp -= iter->len;
> +      write_memory (sp, iter->data, iter->len);
> +    }
> +
> +  /* Finally, update the SP register.  */
> +  regcache_cooked_write_unsigned (regcache, CSKY_SP_REGNUM, sp);
> +  return sp;
> +}
> +
> +/* Implement the return_value gdbarch method.  */
> +
> +static enum return_value_convention
> +csky_return_value (struct gdbarch *gdbarch, struct value *function,
> +                  struct type *valtype, struct regcache *regcache,
> +                  gdb_byte *readbuf, const gdb_byte *writebuf)
> +{
> +  CORE_ADDR regval;
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  int len = TYPE_LENGTH (valtype);
> +  unsigned int ret_regnum = CSKY_RET_REGNUM;
> +
> +  /* Csky abi specifies that return values larger than 8 bytes
> +     are put on the stack.  */
> +  if (len > 8)
> +    return RETURN_VALUE_STRUCT_CONVENTION;
> +  else
> +    {
> +      if (readbuf != NULL)
> +       {
> +         ULONGEST tmp;
> +         /* By using store_unsigned_integer we avoid having to do
> +            anything special for small big-endian values.  */
> +         regcache->cooked_read (ret_regnum, &tmp);
> +         store_unsigned_integer (readbuf, (len > 4 ? 4 : len),
> +                                 byte_order, tmp);
> +         if (len > 4)
> +           {
> +             regcache->cooked_read (ret_regnum + 1, &tmp);
> +             store_unsigned_integer (readbuf + 4,  4, byte_order, tmp);
> +           }
> +       }
> +      if (writebuf != NULL)
> +       {
> +         regval = extract_unsigned_integer (writebuf, len > 4 ? 4 : len,
> +                                            byte_order);
> +         regcache_cooked_write_unsigned (regcache, ret_regnum, regval);
> +         if (len > 4)
> +           {
> +             regval = extract_unsigned_integer ((gdb_byte *) writebuf + 4,
> +                                                4, byte_order);
> +             regcache_cooked_write_unsigned (regcache, ret_regnum + 1,
> +                                             regval);
> +           }
> +
> +       }
> +      return RETURN_VALUE_REGISTER_CONVENTION;
> +    }
> +}
> +
> +/* Implement the frame_align gdbarch method.
> +
> +   Adjust the address downward (direction of stack growth) so that it
> +   is correctly aligned for a new stack frame.  */
> +
> +static CORE_ADDR
> +csky_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  return align_down (addr, 4);
> +}
> +
> +/* Unwind cache used for gdbarch fallback unwinder.  */
> +
> +struct csky_unwind_cache
> +{
> +  /* The stack pointer at the time this frame was created; i.e. the
> +     caller's stack pointer when this function was called.  It is used
> +     to identify this frame.  */
> +  CORE_ADDR prev_sp;
> +
> +  /* The frame base for this frame is just prev_sp - frame size.
> +     FRAMESIZE is the distance from the frame pointer to the
> +     initial stack pointer.  */
> +  int framesize;
> +
> +  /* The register used to hold the frame pointer for this frame.  */
> +  int framereg;
> +
> +  /* Saved register offsets.  */
> +  struct trad_frame_saved_reg *saved_regs;
> +};
> +
> +/* Do prologue analysis, returning the PC of the first instruction
> +   after the function prologue.  */
> +
> +static CORE_ADDR
> +csky_analyze_prologue (struct gdbarch *gdbarch,
> +                      CORE_ADDR start_pc,
> +                      CORE_ADDR limit_pc,
> +                      CORE_ADDR end_pc,
> +                      struct frame_info *this_frame,
> +                      struct csky_unwind_cache *this_cache,
> +                      lr_type_t lr_type)
> +{
> +  CORE_ADDR addr;
> +  CORE_ADDR sp;
> +  CORE_ADDR stack_size;
> +  unsigned int insn, rn;
> +  int status;
> +  int flags;
> +  int framesize = 0;
> +  int stacksize = 0;
> +  int register_offsets[CSKY_NUM_GREGS_SAVED_GREGS];
> +  int insn_len;
> +  /* For adjusting fp.  */
> +  int is_fp_saved = 0;
> +  int adjust_fp = 0;
> +
> +  /* REGISTER_OFFSETS will contain offsets from the top of the frame
> +     (NOT the frame pointer) for the various saved registers, or -1
> +     if the register is not saved.  */
> +  for (rn = 0; rn < CSKY_NUM_GREGS_SAVED_GREGS; rn++)
> +    register_offsets[rn] = -1;
> +
> +  /* Analyze the prologue.  Things we determine from analyzing the
> +     prologue include the size of the frame and which registers are
> +     saved (and where).  */
> +  if (csky_debug)
> +    {
> +      fprintf_unfiltered (gdb_stdlog,
> +                         "csky: Scanning prologue: start_pc = 0x%x,"
> +                         "limit_pc = 0x%x\n", (unsigned int) start_pc,
> +                         (unsigned int) limit_pc);
> +    }
> +
> +  /* Default to 16 bit instruction.  */
> +  insn_len = 2;
> +  stacksize = 0;
> +  for (addr = start_pc; addr < limit_pc; addr += insn_len)
> +    {
> +      /* Get next insn.  */
> +      insn_len = csky_get_insn (gdbarch, addr, &insn);
> +
> +      /* Check if 32 bit.  */
> +      if (insn_len == 4)
> +       {
> +         /* subi32 sp,sp oimm12.  */
> +         if (CSKY_32_IS_SUBI0 (insn))
> +           {
> +             /* Got oimm12.  */
> +             int offset = CSKY_32_SUBI_IMM (insn);
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: got subi sp,%d; continuing\n",
> +                                     offset);
> +               }
> +             stacksize += offset;
> +             continue;
> +           }
> +         /* stm32 ry-rz,(sp).  */
> +         else if (CSKY_32_IS_STMx0 (insn))
> +           {
> +             /* Spill register(s).  */
> +             int start_register;
> +             int reg_count;
> +             int offset;
> +
> +             /* BIG WARNING! The CKCore ABI does not restrict functions
> +                to taking only one stack allocation.  Therefore, when
> +                we save a register, we record the offset of where it was
> +                saved relative to the current stacksize.  This will
> +                then give an offset from the SP upon entry to our
> +                function.  Remember, stacksize is NOT constant until
> +                we're done scanning the prologue.  */
> +             start_register = CSKY_32_STM_VAL_REGNUM (insn);
> +             reg_count = CSKY_32_STM_SIZE (insn);
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: got stm r%d-r%d,(sp)\n",
> +                                     start_register,
> +                                     start_register + reg_count);
> +               }
> +
> +             for (rn = start_register, offset = 0;
> +                  rn <= start_register + reg_count;
> +                  rn++, offset += 4)
> +               {
> +                 register_offsets[rn] = stacksize - offset;
> +                 if (csky_debug)
> +                   {
> +                     fprintf_unfiltered (gdb_stdlog,
> +                                         "csky: r%d saved at 0x%x"
> +                                         " (offset %d)\n",
> +                                         rn, register_offsets[rn],
> +                                         offset);
> +                   }
> +               }
> +             if (csky_debug)
> +               fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
> +             continue;
> +           }
> +         /* stw ry,(sp,disp).  */
> +         else if (CSKY_32_IS_STWx0 (insn))
> +           {
> +             /* Spill register: see note for IS_STM above.  */
> +             int disp;
> +
> +             rn = CSKY_32_ST_VAL_REGNUM (insn);
> +             disp = CSKY_32_ST_OFFSET (insn);
> +             register_offsets[rn] = stacksize - disp;
> +             if (csky_debug)
> +               print_savedreg_msg (rn, register_offsets, true);
> +             continue;
> +           }
> +         else if (CSKY_32_IS_MOV_FP_SP (insn))
> +           {
> +             /* SP is saved to FP reg, means code afer prologue may
> +                modify SP.  */
> +             is_fp_saved = 1;
> +             adjust_fp = stacksize;
> +             continue;
> +           }
> +         else if (CSKY_32_IS_MFCR_EPSR (insn))
> +           {
> +             unsigned int insn2;
> +             addr += 4;
> +             int mfcr_regnum = insn & 0x1f;
> +             insn_len = csky_get_insn (gdbarch, addr, &insn2);
> +             if (insn_len == 2)
> +               {
> +                 int stw_regnum = (insn2 >> 5) & 0x7;
> +                 if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
> +                   {
> +                     int offset;
> +
> +                     /* CSKY_EPSR_REGNUM.  */
> +                     rn  = CSKY_NUM_GREGS;
> +                     offset = CSKY_16_STWx0_OFFSET (insn2);
> +                     register_offsets[rn] = stacksize - offset;
> +                     if (csky_debug)
> +                       print_savedreg_msg (rn, register_offsets, true);
> +                     continue;
> +                   }
> +                 break;
> +               }
> +             else
> +               {
> +                 /* INSN_LEN == 4.  */
> +                 int stw_regnum = (insn2 >> 21) & 0x1f;
> +                 if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
> +                   {
> +                     int offset;
> +
> +                     /* CSKY_EPSR_REGNUM.  */
> +                     rn  = CSKY_NUM_GREGS;
> +                     offset = CSKY_32_ST_OFFSET (insn2);
> +                     register_offsets[rn] = framesize - offset;
> +                     if (csky_debug)
> +                       print_savedreg_msg (rn, register_offsets, true);
> +                     continue;
> +                   }
> +                 break;
> +               }
> +           }
> +         else if (CSKY_32_IS_MFCR_FPSR (insn))
> +           {
> +             unsigned int insn2;
> +             addr += 4;
> +             int mfcr_regnum = insn & 0x1f;
> +             insn_len = csky_get_insn (gdbarch, addr, &insn2);
> +             if (insn_len == 2)
> +               {
> +                 int stw_regnum = (insn2 >> 5) & 0x7;
> +                 if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum
> +                                                == stw_regnum))
> +                   {
> +                     int offset;
> +
> +                     /* CSKY_FPSR_REGNUM.  */
> +                     rn  = CSKY_NUM_GREGS + 1;
> +                     offset = CSKY_16_STWx0_OFFSET (insn2);
> +                     register_offsets[rn] = stacksize - offset;
> +                     if (csky_debug)
> +                       print_savedreg_msg (rn, register_offsets, true);
> +                     continue;
> +                   }
> +                 break;
> +               }
> +             else
> +               {
> +                 /* INSN_LEN == 4.  */
> +                 int stw_regnum = (insn2 >> 21) & 0x1f;
> +                 if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
> +                   {
> +                     int offset;
> +
> +                     /* CSKY_FPSR_REGNUM.  */
> +                     rn  = CSKY_NUM_GREGS + 1;
> +                     offset = CSKY_32_ST_OFFSET (insn2);
> +                     register_offsets[rn] = framesize - offset;
> +                     if (csky_debug)
> +                       print_savedreg_msg (rn, register_offsets, true);
> +                     continue;
> +                   }
> +                 break;
> +               }
> +           }
> +         else if (CSKY_32_IS_MFCR_EPC (insn))
> +           {
> +             unsigned int insn2;
> +             addr += 4;
> +             int mfcr_regnum = insn & 0x1f;
> +             insn_len = csky_get_insn (gdbarch, addr, &insn2);
> +             if (insn_len == 2)
> +               {
> +                 int stw_regnum = (insn2 >> 5) & 0x7;
> +                 if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
> +                   {
> +                     int offset;
> +
> +                     /* CSKY_EPC_REGNUM.  */
> +                     rn  = CSKY_NUM_GREGS + 2;
> +                     offset = CSKY_16_STWx0_OFFSET (insn2);
> +                     register_offsets[rn] = stacksize - offset;
> +                     if (csky_debug)
> +                       print_savedreg_msg (rn, register_offsets, true);
> +                     continue;
> +                   }
> +                 break;
> +               }
> +             else
> +               {
> +                 /* INSN_LEN == 4.  */
> +                 int stw_regnum = (insn2 >> 21) & 0x1f;
> +                 if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
> +                   {
> +                     int offset;
> +
> +                     /* CSKY_EPC_REGNUM.  */
> +                     rn  = CSKY_NUM_GREGS + 2;
> +                     offset = CSKY_32_ST_OFFSET (insn2);
> +                     register_offsets[rn] = framesize - offset;
> +                     if (csky_debug)
> +                       print_savedreg_msg (rn, register_offsets, true);
> +                     continue;
> +                   }
> +                 break;
> +               }
> +           }
> +         else if (CSKY_32_IS_MFCR_FPC (insn))
> +           {
> +             unsigned int insn2;
> +             addr += 4;
> +             int mfcr_regnum = insn & 0x1f;
> +             insn_len = csky_get_insn (gdbarch, addr, &insn2);
> +             if (insn_len == 2)
> +               {
> +                 int stw_regnum = (insn2 >> 5) & 0x7;
> +                 if (CSKY_16_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
> +                   {
> +                     int offset;
> +
> +                     /* CSKY_FPC_REGNUM.  */
> +                     rn  = CSKY_NUM_GREGS + 3;
> +                     offset = CSKY_16_STWx0_OFFSET (insn2);
> +                     register_offsets[rn] = stacksize - offset;
> +                     if (csky_debug)
> +                       print_savedreg_msg (rn, register_offsets, true);
> +                     continue;
> +                   }
> +                 break;
> +               }
> +             else
> +               {
> +                 /* INSN_LEN == 4.  */
> +                 int stw_regnum = (insn2 >> 21) & 0x1f;
> +                 if (CSKY_32_IS_STWx0 (insn2) && (mfcr_regnum == stw_regnum))
> +                   {
> +                     int offset;
> +
> +                     /* CSKY_FPC_REGNUM.  */
> +                     rn  = CSKY_NUM_GREGS + 3;
> +                     offset = CSKY_32_ST_OFFSET (insn2);
> +                     register_offsets[rn] = framesize - offset;
> +                     if (csky_debug)
> +                       print_savedreg_msg (rn, register_offsets, true);
> +                     continue;
> +                   }
> +                 break;
> +               }
> +           }
> +         else if (CSKY_32_IS_PUSH (insn))
> +           {
> +             /* Push for 32_bit.  */
> +             int offset = 0;
> +             if (CSKY_32_IS_PUSH_R29 (insn))
> +               {
> +                 stacksize += 4;
> +                 register_offsets[29] = stacksize;
> +                 if (csky_debug)
> +                   print_savedreg_msg (29, register_offsets, false);
> +                 offset += 4;
> +               }
> +             if (CSKY_32_PUSH_LIST2 (insn))
> +               {
> +                 int num = CSKY_32_PUSH_LIST2 (insn);
> +                 int tmp = 0;
> +                 stacksize += num * 4;
> +                 offset += num * 4;
> +                 if (csky_debug)
> +                   {
> +                     fprintf_unfiltered (gdb_stdlog,
> +                                         "csky: push regs_array: r16-r%d\n",
> +                                         16 + num - 1);
> +                   }
> +                 for (rn = 16; rn <= 16 + num - 1; rn++)
> +                   {
> +                      register_offsets[rn] = stacksize - tmp;
> +                      if (csky_debug)
> +                        {
> +                          fprintf_unfiltered (gdb_stdlog,
> +                                              "csky: r%d saved at 0x%x"
> +                                              " (offset %d)\n", rn,
> +                                              register_offsets[rn], tmp);
> +                        }
> +                      tmp += 4;
> +                   }
> +               }
> +             if (CSKY_32_IS_PUSH_R15 (insn))
> +               {
> +                 stacksize += 4;
> +                 register_offsets[15] = stacksize;
> +                 if (csky_debug)
> +                   print_savedreg_msg (15, register_offsets, false);
> +                 offset += 4;
> +               }
> +             if (CSKY_32_PUSH_LIST1 (insn))
> +               {
> +                 int num = CSKY_32_PUSH_LIST1 (insn);
> +                 int tmp = 0;
> +                 stacksize += num * 4;
> +                 offset += num * 4;
> +                 if (csky_debug)
> +                   {
> +                     fprintf_unfiltered (gdb_stdlog,
> +                                         "csky: push regs_array: r4-r%d\n",
> +                                         4 + num - 1);
> +                   }
> +                 for (rn = 4; rn <= 4 + num - 1; rn++)
> +                   {
> +                      register_offsets[rn] = stacksize - tmp;
> +                      if (csky_debug)
> +                        {
> +                          fprintf_unfiltered (gdb_stdlog,
> +                                              "csky: r%d saved at 0x%x"
> +                                              " (offset %d)\n", rn,
> +                                              register_offsets[rn], tmp);
> +                        }
> +                       tmp += 4;
> +                   }
> +               }
> +
> +             framesize = stacksize;
> +             if (csky_debug)
> +               fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
> +             continue;
> +           }
> +         else if (CSKY_32_IS_LRW4 (insn) || CSKY_32_IS_MOVI4 (insn)
> +                  || CSKY_32_IS_MOVIH4 (insn) || CSKY_32_IS_BMASKI4 (insn))
> +           {
> +             int adjust = 0;
> +             int offset = 0;
> +             unsigned int insn2;
> +
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: looking at large frame\n");
> +               }
> +             if (CSKY_32_IS_LRW4 (insn))
> +               {
> +                 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +                 int literal_addr = (addr + ((insn & 0xffff) << 2))
> +                                    & 0xfffffffc;
> +                 adjust = read_memory_unsigned_integer (literal_addr, 4,
> +                                                        byte_order);
> +               }
> +             else if (CSKY_32_IS_MOVI4 (insn))
> +               adjust = (insn  & 0xffff);
> +             else if (CSKY_32_IS_MOVIH4 (insn))
> +               adjust = (insn & 0xffff) << 16;
> +             else
> +               {
> +                 /* CSKY_32_IS_BMASKI4 (insn).  */
> +                 adjust = (1 << (((insn & 0x3e00000) >> 21) + 1)) - 1;
> +               }
> +
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: base stacksize=0x%x\n", adjust);
> +
> +                 /* May have zero or more insns which modify r4.  */
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: looking for r4 adjusters...\n");
> +               }
> +
> +             offset = 4;
> +             insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
> +             while (CSKY_IS_R4_ADJUSTER (insn2))
> +               {
> +                 if (CSKY_32_IS_ADDI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0xfff) + 1;
> +                     adjust += imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: addi r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_SUBI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0xfff) + 1;
> +                     adjust -= imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: subi r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_NOR4 (insn2))
> +                   {
> +                     adjust = ~adjust;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: nor r4,r4,r4\n");
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_ROTLI4 (insn2))
> +                   {
> +                     int imm = ((insn2 >> 21) & 0x1f);
> +                     int temp = adjust >> (32 - imm);
> +                     adjust <<= imm;
> +                     adjust |= temp;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: rotli r4,r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_LISI4 (insn2))
> +                   {
> +                     int imm = ((insn2 >> 21) & 0x1f);
> +                     adjust <<= imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: lsli r4,r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_BSETI4 (insn2))
> +                   {
> +                     int imm = ((insn2 >> 21) & 0x1f);
> +                     adjust |= (1 << imm);
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: bseti r4,r4 %d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_BCLRI4 (insn2))
> +                   {
> +                     int imm = ((insn2 >> 21) & 0x1f);
> +                     adjust &= ~(1 << imm);
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: bclri r4,r4 %d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_IXH4 (insn2))
> +                   {
> +                     adjust *= 3;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: ixh r4,r4,r4\n");
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_IXW4 (insn2))
> +                   {
> +                     adjust *= 5;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: ixw r4,r4,r4\n");
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_ADDI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0xff) + 1;
> +                     adjust += imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: addi r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_SUBI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0xff) + 1;
> +                     adjust -= imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: subi r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_NOR4 (insn2))
> +                   {
> +                     adjust = ~adjust;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: nor r4,r4\n");
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_BSETI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0x1f);
> +                     adjust |= (1 << imm);
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: bseti r4, %d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_BCLRI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0x1f);
> +                     adjust &= ~(1 << imm);
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: bclri r4, %d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_LSLI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0x1f);
> +                     adjust <<= imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: lsli r4,r4, %d\n", imm);
> +                       }
> +                   }
> +
> +                 offset += insn_len;
> +                 insn_len =  csky_get_insn (gdbarch, addr + offset, &insn2);
> +               };
> +
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog, "csky: done looking for"
> +                                     " r4 adjusters\n");
> +               }
> +
> +             /* If the next insn adjusts the stack pointer, we keep
> +                everything; if not, we scrap it and we've found the
> +                end of the prologue.  */
> +             if (CSKY_IS_SUBU4 (insn2))
> +               {
> +                 addr += offset;
> +                 stacksize += adjust;
> +                 if (csky_debug)
> +                   {
> +                     fprintf_unfiltered (gdb_stdlog,
> +                                         "csky: found stack adjustment of"
> +                                         " 0x%x bytes.\n", adjust);
> +                     fprintf_unfiltered (gdb_stdlog,
> +                                         "csky: skipping to new address "
> +                                         "0x%lx\n", addr);
> +                     fprintf_unfiltered (gdb_stdlog,
> +                                         "csky: continuing\n");
> +                   }
> +                 continue;
> +               }
> +
> +             /* None of these instructions are prologue, so don't touch
> +                anything.  */
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: no subu sp,sp,r4; NOT altering"
> +                                     " stacksize.\n");
> +               }
> +             break;
> +           }
> +       }
> +      else
> +       {
> +         /* insn_len != 4.  */
> +
> +         /* subi.sp sp,disp.  */
> +         if (CSKY_16_IS_SUBI0 (insn))
> +           {
> +             int offset = CSKY_16_SUBI_IMM (insn);
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: got subi r0,%d; continuing\n",
> +                                     offset);
> +               }
> +             stacksize += offset;
> +             continue;
> +           }
> +         /* stw.16 rz,(sp,disp).  */
> +         else if (CSKY_16_IS_STWx0 (insn))
> +           {
> +             /* Spill register: see note for IS_STM above.  */
> +             int disp;
> +
> +             rn = CSKY_16_ST_VAL_REGNUM (insn);
> +             disp = CSKY_16_ST_OFFSET (insn);
> +             register_offsets[rn] = stacksize - disp;
> +             if (csky_debug)
> +               print_savedreg_msg (rn, register_offsets, true);
> +             continue;
> +           }
> +         else if (CSKY_16_IS_MOV_FP_SP (insn))
> +           {
> +             /* SP is saved to FP reg, means prologue may modify SP.  */
> +             is_fp_saved = 1;
> +             adjust_fp = stacksize;
> +             continue;
> +           }
> +         else if (CSKY_16_IS_PUSH (insn))
> +           {
> +             /* Push for 16_bit.  */
> +             int offset = 0;
> +             if (CSKY_16_IS_PUSH_R15 (insn))
> +               {
> +                 stacksize += 4;
> +                 register_offsets[15] = stacksize;
> +                 if (csky_debug)
> +                   print_savedreg_msg (15, register_offsets, false);
> +                 offset += 4;
> +                }
> +             if (CSKY_16_PUSH_LIST1 (insn))
> +               {
> +                 int num = CSKY_16_PUSH_LIST1 (insn);
> +                 int tmp = 0;
> +                 stacksize += num * 4;
> +                 offset += num * 4;
> +                 if (csky_debug)
> +                   {
> +                     fprintf_unfiltered (gdb_stdlog,
> +                                         "csky: push regs_array: r4-r%d\n",
> +                                         4 + num - 1);
> +                   }
> +                 for (rn = 4; rn <= 4 + num - 1; rn++)
> +                   {
> +                      register_offsets[rn] = stacksize - tmp;
> +                      if (csky_debug)
> +                        {
> +                          fprintf_unfiltered (gdb_stdlog,
> +                                              "csky: r%d saved at 0x%x"
> +                                              " (offset %d)\n", rn,
> +                                              register_offsets[rn], offset);
> +                        }
> +                      tmp += 4;
> +                   }
> +               }
> +
> +             framesize = stacksize;
> +             if (csky_debug)
> +               fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
> +             continue;
> +           }
> +         else if (CSKY_16_IS_LRW4 (insn) || CSKY_16_IS_MOVI4 (insn))
> +           {
> +             int adjust = 0;
> +             int offset = 0;
> +             unsigned int insn2;
> +
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: looking at large frame\n");
> +               }
> +             if (CSKY_16_IS_LRW4 (insn))
> +               {
> +                 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +                 int offset = ((insn & 0x300) >> 3) | (insn & 0x1f);
> +                 int literal_addr = (addr + ( offset << 2)) & 0xfffffffc;
> +                 adjust = read_memory_unsigned_integer (literal_addr, 4,
> +                                                        byte_order);
> +               }
> +             else
> +               {
> +                 /* CSKY_16_IS_MOVI4 (insn).  */
> +                 adjust = (insn  & 0xff);
> +               }
> +
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: base stacksize=0x%x\n", adjust);
> +               }
> +
> +             /* May have zero or more instructions which modify r4.  */
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog,
> +                                     "csky: looking for r4 adjusters...\n");
> +               }
> +             offset = 2;
> +             insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
> +             while (CSKY_IS_R4_ADJUSTER (insn2))
> +               {
> +                 if (CSKY_32_IS_ADDI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0xfff) + 1;
> +                     adjust += imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: addi r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_SUBI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0xfff) + 1;
> +                     adjust -= imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: subi r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_NOR4 (insn2))
> +                   {
> +                     adjust = ~adjust;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: nor r4,r4,r4\n");
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_ROTLI4 (insn2))
> +                   {
> +                     int imm = ((insn2 >> 21) & 0x1f);
> +                     int temp = adjust >> (32 - imm);
> +                     adjust <<= imm;
> +                     adjust |= temp;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: rotli r4,r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_LISI4 (insn2))
> +                   {
> +                     int imm = ((insn2 >> 21) & 0x1f);
> +                     adjust <<= imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: lsli r4,r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_BSETI4 (insn2))
> +                   {
> +                     int imm = ((insn2 >> 21) & 0x1f);
> +                     adjust |= (1 << imm);
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: bseti r4,r4 %d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_BCLRI4 (insn2))
> +                   {
> +                     int imm = ((insn2 >> 21) & 0x1f);
> +                     adjust &= ~(1 << imm);
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: bclri r4,r4 %d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_IXH4 (insn2))
> +                   {
> +                     adjust *= 3;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: ixh r4,r4,r4\n");
> +                       }
> +                   }
> +                 else if (CSKY_32_IS_IXW4 (insn2))
> +                   {
> +                     adjust *= 5;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: ixw r4,r4,r4\n");
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_ADDI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0xff) + 1;
> +                     adjust += imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: addi r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_SUBI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0xff) + 1;
> +                     adjust -= imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: subi r4,%d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_NOR4 (insn2))
> +                   {
> +                     adjust = ~adjust;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: nor r4,r4\n");
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_BSETI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0x1f);
> +                     adjust |= (1 << imm);
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: bseti r4, %d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_BCLRI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0x1f);
> +                     adjust &= ~(1 << imm);
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: bclri r4, %d\n", imm);
> +                       }
> +                   }
> +                 else if (CSKY_16_IS_LSLI4 (insn2))
> +                   {
> +                     int imm = (insn2 & 0x1f);
> +                     adjust <<= imm;
> +                     if (csky_debug)
> +                       {
> +                         fprintf_unfiltered (gdb_stdlog,
> +                                             "csky: lsli r4,r4, %d\n", imm);
> +                       }
> +                   }
> +
> +                 offset += insn_len;
> +                 insn_len = csky_get_insn (gdbarch, addr + offset, &insn2);
> +               };
> +
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog, "csky: "
> +                                     "done looking for r4 adjusters\n");
> +               }
> +
> +             /* If the next instruction adjusts the stack pointer, we keep
> +                everything; if not, we scrap it and we've found the end
> +                of the prologue.  */
> +             if (CSKY_IS_SUBU4 (insn2))
> +               {
> +                 addr += offset;
> +                 stacksize += adjust;
> +                 if (csky_debug)
> +                   {
> +                     fprintf_unfiltered (gdb_stdlog, "csky: "
> +                                         "found stack adjustment of 0x%x"
> +                                         " bytes.\n", adjust);
> +                     fprintf_unfiltered (gdb_stdlog, "csky: "
> +                                         "skipping to new address 0x%lx\n",
> +                                         addr);
> +                     fprintf_unfiltered (gdb_stdlog, "csky: continuing\n");
> +                   }
> +                 continue;
> +               }
> +
> +             /* None of these instructions are prologue, so don't touch
> +                anything.  */
> +             if (csky_debug)
> +               {
> +                 fprintf_unfiltered (gdb_stdlog, "csky: no subu sp,r4; "
> +                                     "NOT altering stacksize.\n");
> +               }
> +             break;
> +           }
> +       }
> +
> +      /* This is not a prologue instruction, so stop here.  */
> +      if (csky_debug)
> +       {
> +         fprintf_unfiltered (gdb_stdlog, "csky: insn is not a prologue"
> +                             " insn -- ending scan\n");
> +       }
> +      break;
> +    }
> +
> +  if (this_cache)
> +    {
> +      CORE_ADDR unwound_fp;
> +      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +      this_cache->framesize = framesize;
> +
> +      if (is_fp_saved)
> +       {
> +         this_cache->framereg = CSKY_FP_REGNUM;
> +         unwound_fp = get_frame_register_unsigned (this_frame,
> +                                                   this_cache->framereg);
> +         this_cache->prev_sp = unwound_fp + adjust_fp;
> +       }
> +      else
> +       {
> +         this_cache->framereg = CSKY_SP_REGNUM;
> +         unwound_fp = get_frame_register_unsigned (this_frame,
> +                                                   this_cache->framereg);
> +         this_cache->prev_sp = unwound_fp + stacksize;
> +       }
> +
> +      /* Note where saved registers are stored.  The offsets in
> +        REGISTER_OFFSETS are computed relative to the top of the frame.  */
> +      for (rn = 0; rn < CSKY_NUM_GREGS; rn++)
> +       {
> +         if (register_offsets[rn] >= 0)
> +           {
> +             this_cache->saved_regs[rn].addr
> +               = this_cache->prev_sp - register_offsets[rn];
> +             if (csky_debug)
> +               {
> +                 CORE_ADDR rn_value = read_memory_unsigned_integer (
> +                   this_cache->saved_regs[rn].addr, 4, byte_order);
> +                 fprintf_unfiltered (gdb_stdlog, "Saved register %s "
> +                                     "stored at 0x%08lx, value=0x%08lx\n",
> +                                     csky_register_names[rn],
> +                                     (unsigned long)
> +                                       this_cache->saved_regs[rn].addr,
> +                                     (unsigned long) rn_value);
> +               }
> +           }
> +       }
> +      if (lr_type == LR_TYPE_EPC)
> +       {
> +         /* rte || epc .  */
> +         this_cache->saved_regs[CSKY_PC_REGNUM]
> +           = this_cache->saved_regs[CSKY_EPC_REGNUM];
> +       }
> +      else if (lr_type == LR_TYPE_FPC)
> +       {
> +         /* rfi || fpc .  */
> +         this_cache->saved_regs[CSKY_PC_REGNUM]
> +           = this_cache->saved_regs[CSKY_FPC_REGNUM];
> +       }
> +      else
> +       {
> +         this_cache->saved_regs[CSKY_PC_REGNUM]
> +           = this_cache->saved_regs[CSKY_LR_REGNUM];
> +       }
> +    }
> +
> +  return addr;
> +}
> +
> +/* Detect whether PC is at a point where the stack frame has been
> +   destroyed.  */
> +
> +static int
> +csky_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
> +{
> +  unsigned int insn;
> +  CORE_ADDR addr;
> +  CORE_ADDR func_start, func_end;
> +
> +  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
> +    return 0;
> +
> +  bool fp_saved = false;
> +  int insn_len;
> +  for (addr = func_start; addr < func_end; addr += insn_len)
> +    {
> +      /* Get next insn.  */
> +      insn_len = csky_get_insn (gdbarch, addr, &insn);
> +
> +      if (insn_len == 2)
> +       {
> +         /* Is sp is saved to fp.  */
> +         if (CSKY_16_IS_MOV_FP_SP (insn))
> +           fp_saved = true;
> +         /* If sp was saved to fp and now being restored from
> +            fp then it indicates the start of epilog.  */
> +         else if (fp_saved && CSKY_16_IS_MOV_SP_FP (insn))
> +           return pc >= addr;
> +       }
> +    }
> +  return 0;
> +}
> +
> +/* Implement the skip_prologue gdbarch hook.  */
> +
> +static CORE_ADDR
> +csky_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
> +{
> +  CORE_ADDR func_addr, func_end;
> +  struct symtab_and_line sal;
> +  LONGEST return_value;
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  const int default_search_limit = 128;
> +
> +  /* See if we can find the end of the prologue using the symbol table.  */
> +  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
> +    {
> +      CORE_ADDR post_prologue_pc
> +       = skip_prologue_using_sal (gdbarch, func_addr);
> +
> +      if (post_prologue_pc != 0)
> +       return std::max (pc, post_prologue_pc);
> +    }
> +  else
> +    func_end = pc + default_search_limit;
> +
> +  /* Find the end of prologue.  Default lr_type.  */
> +  return csky_analyze_prologue (gdbarch, pc, func_end, func_end,
> +                               NULL, NULL, LR_TYPE_R15);
> +}
> +
> +/* Implement the breakpoint_kind_from_pc gdbarch method.  */
> +
> +static int
> +csky_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
> +{
> +  if (csky_pc_is_csky16 (gdbarch, *pcptr))
> +    return CSKY_INSN_SIZE16;
> +  else
> +    return CSKY_INSN_SIZE32;
> +}
> +
> +/* Implement the sw_breakpoint_from_kind gdbarch method.  */
> +
> +static const gdb_byte *
> +csky_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
> +{
> +  *size = kind;
> +  if (kind == CSKY_INSN_SIZE16)
> +    {
> +      static gdb_byte csky_16_breakpoint[] = { 0, 0 };
> +      return csky_16_breakpoint;
> +    }
> +  else
> +    {
> +      static gdb_byte csky_32_breakpoint[] = { 0, 0, 0, 0 };
> +      return csky_32_breakpoint;
> +    }
> +}
> +
> +/* Implement the memory_insert_breakpoint gdbarch method.  */
> +
> +static int
> +csky_memory_insert_breakpoint (struct gdbarch *gdbarch,
> +                              struct bp_target_info *bp_tgt)
> +{
> +  int val;
> +  const unsigned char *bp;
> +  gdb_byte bp_write_record1[] = { 0, 0, 0, 0 };
> +  gdb_byte bp_write_record2[] = { 0, 0, 0, 0 };
> +  gdb_byte bp_record[] = { 0, 0, 0, 0 };
> +
> +  /* Sanity-check bp_address.  */
> +  if (bp_tgt->reqstd_address % 2)
> +    warning (_("Invalid breakpoint address 0x%x is an odd number.\n"),
> +            (unsigned int) bp_tgt->reqstd_address);
> +  scoped_restore restore_memory
> +    = make_scoped_restore_show_memory_breakpoints (1);
> +
> +  /* Determine appropriate breakpoint_kind for this address.  */
> +  bp_tgt->kind = csky_breakpoint_kind_from_pc (gdbarch,
> +                                              &bp_tgt->reqstd_address);
> +
> +  /* Save the memory contents.  */
> +  bp_tgt->shadow_len = bp_tgt->kind;
> +
> +  /* Fill bp_tgt->placed_address.  */
> +  bp_tgt->placed_address = bp_tgt->reqstd_address;
> +
> +  if (bp_tgt->kind == CSKY_INSN_SIZE16)
> +    {
> +      if ((bp_tgt->reqstd_address % 4) == 0)
> +       {
> +         /* Read two bytes.  */
> +         val = target_read_memory (bp_tgt->reqstd_address,
> +                                   bp_tgt->shadow_contents, 2);
> +         if (val)
> +           return val;
> +
> +         /* Read two bytes.  */
> +         val = target_read_memory (bp_tgt->reqstd_address + 2,
> +                                   bp_record, 2);
> +         if (val)
> +           return val;
> +
> +         /* Write the breakpoint.  */
> +         bp_write_record1[2] = bp_record[0];
> +         bp_write_record1[3] = bp_record[1];
> +         bp = bp_write_record1;
> +         val = target_write_raw_memory (bp_tgt->reqstd_address, bp,
> +                                        CSKY_WR_BKPT_MODE);
> +       }
> +      else
> +       {
> +         val = target_read_memory (bp_tgt->reqstd_address,
> +                                   bp_tgt->shadow_contents, 2);
> +         if (val)
> +           return val;
> +
> +         val = target_read_memory (bp_tgt->reqstd_address - 2,
> +                                   bp_record, 2);
> +         if (val)
> +           return val;
> +
> +         /* Write the breakpoint.  */
> +         bp_write_record1[0] = bp_record[0];
> +         bp_write_record1[1] = bp_record[1];
> +         bp = bp_write_record1;
> +         val = target_write_raw_memory (bp_tgt->reqstd_address - 2,
> +                                        bp, CSKY_WR_BKPT_MODE);
> +       }
> +    }
> +  else
> +    {
> +      if (bp_tgt->placed_address % 4 == 0)
> +       {
> +         val = target_read_memory (bp_tgt->reqstd_address,
> +                                   bp_tgt->shadow_contents,
> +                                   CSKY_WR_BKPT_MODE);
> +         if (val)
> +           return val;
> +
> +         /* Write the breakpoint.  */
> +         bp = bp_write_record1;
> +         val = target_write_raw_memory (bp_tgt->reqstd_address,
> +                                        bp, CSKY_WR_BKPT_MODE);
> +       }
> +      else
> +       {
> +         val = target_read_memory (bp_tgt->reqstd_address,
> +                                   bp_tgt->shadow_contents,
> +                                   CSKY_WR_BKPT_MODE);
> +         if (val)
> +           return val;
> +
> +         val = target_read_memory (bp_tgt->reqstd_address - 2,
> +                                   bp_record, 2);
> +         if (val)
> +           return val;
> +
> +         val = target_read_memory (bp_tgt->reqstd_address + 4,
> +                                   bp_record + 2, 2);
> +         if (val)
> +           return val;
> +
> +         bp_write_record1[0] = bp_record[0];
> +         bp_write_record1[1] = bp_record[1];
> +         bp_write_record2[2] = bp_record[2];
> +         bp_write_record2[3] = bp_record[3];
> +
> +         /* Write the breakpoint.  */
> +         bp = bp_write_record1;
> +         val = target_write_raw_memory (bp_tgt->reqstd_address - 2, bp,
> +                                        CSKY_WR_BKPT_MODE);
> +         if (val)
> +           return val;
> +
> +         /* Write the breakpoint.  */
> +         bp = bp_write_record2;
> +         val = target_write_raw_memory (bp_tgt->reqstd_address + 2, bp,
> +                                        CSKY_WR_BKPT_MODE);
> +       }
> +    }
> +  return val;
> +}
> +
> +/* Restore the breakpoint shadow_contents to the target.  */
> +
> +static int
> +csky_memory_remove_breakpoint (struct gdbarch *gdbarch,
> +                              struct bp_target_info *bp_tgt)
> +{
> +  int val;
> +  gdb_byte bp_record[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
> +  /* Different for shadow_len 2 or 4.  */
> +  if (bp_tgt->shadow_len == 2)
> +    {
> +      /* Do word-sized writes on word-aligned boundaries and read
> +        padding bytes as necessary.  */
> +      if (bp_tgt->reqstd_address % 4 == 0)
> +       {
> +         val = target_read_memory (bp_tgt->reqstd_address + 2,
> +                                   bp_record + 2, 2);
> +         if (val)
> +           return val;
> +         bp_record[0] = bp_tgt->shadow_contents[0];
> +         bp_record[1] = bp_tgt->shadow_contents[1];
> +         return target_write_raw_memory (bp_tgt->reqstd_address,
> +                                         bp_record, CSKY_WR_BKPT_MODE);
> +       }
> +      else
> +       {
> +         val = target_read_memory (bp_tgt->reqstd_address - 2,
> +                                   bp_record, 2);
> +         if (val)
> +           return val;
> +         bp_record[2] = bp_tgt->shadow_contents[0];
> +         bp_record[3] = bp_tgt->shadow_contents[1];
> +         return target_write_raw_memory (bp_tgt->reqstd_address - 2,
> +                                         bp_record, CSKY_WR_BKPT_MODE);
> +       }
> +    }
> +  else
> +    {
> +      /* Do word-sized writes on word-aligned boundaries and read
> +        padding bytes as necessary.  */
> +      if (bp_tgt->placed_address % 4 == 0)
> +       {
> +         return target_write_raw_memory (bp_tgt->reqstd_address,
> +                                         bp_tgt->shadow_contents,
> +                                         CSKY_WR_BKPT_MODE);
> +       }
> +      else
> +       {
> +         val = target_read_memory (bp_tgt->reqstd_address - 2,
> +                                   bp_record, 2);
> +         if (val)
> +           return val;
> +         val = target_read_memory (bp_tgt->reqstd_address + 4,
> +                                   bp_record+6, 2);
> +         if (val)
> +           return val;
> +
> +         bp_record[2] = bp_tgt->shadow_contents[0];
> +         bp_record[3] = bp_tgt->shadow_contents[1];
> +         bp_record[4] = bp_tgt->shadow_contents[2];
> +         bp_record[5] = bp_tgt->shadow_contents[3];
> +
> +         return target_write_raw_memory (bp_tgt->reqstd_address - 2,
> +                                         bp_record,
> +                                         CSKY_WR_BKPT_MODE * 2);
> +       }
> +    }
> +}
> +
> +/* Determine link register type.  */
> +
> +static lr_type_t
> +csky_analyze_lr_type (struct gdbarch *gdbarch,
> +                     CORE_ADDR start_pc, CORE_ADDR end_pc)
> +{
> +  CORE_ADDR addr;
> +  unsigned int insn, rn, insn_len;
> +  insn_len = 2;
> +
> +  for (addr = start_pc; addr < end_pc; addr += insn_len)
> +    {
> +      insn_len = csky_get_insn (gdbarch, addr, &insn);
> +      if (insn_len == 4)
> +       {
> +         if (CSKY_32_IS_MFCR_EPSR (insn) || CSKY_32_IS_MFCR_EPC (insn)
> +             || CSKY_32_IS_RTE (insn))
> +           return LR_TYPE_EPC;
> +       }
> +      else if (CSKY_32_IS_MFCR_FPSR (insn) || CSKY_32_IS_MFCR_FPC (insn)
> +              || CSKY_32_IS_RFI (insn))
> +       return LR_TYPE_FPC;
> +      else if (CSKY_32_IS_JMP (insn) || CSKY_32_IS_BR (insn)
> +              || CSKY_32_IS_JMPIX (insn) || CSKY_32_IS_JMPI (insn))
> +       return LR_TYPE_R15;
> +      else
> +       {
> +         /* 16 bit instruction.  */
> +         if (CSKY_16_IS_JMP (insn) || CSKY_16_IS_BR (insn)
> +             || CSKY_16_IS_JMPIX (insn))
> +           return LR_TYPE_R15;
> +       }
> +    }
> +    return LR_TYPE_R15;
> +}
> +
> +/* Heuristic unwinder.  */
> +
> +static struct csky_unwind_cache *
> +csky_frame_unwind_cache (struct frame_info *this_frame)
> +{
> +  CORE_ADDR prologue_start, prologue_end, func_end, prev_pc, block_addr;
> +  struct csky_unwind_cache *cache;
> +  const struct block *bl;
> +  unsigned long func_size = 0;
> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
> +  unsigned int sp_regnum = CSKY_SP_REGNUM;
> +
> +  /* Default lr type is r15.  */
> +  lr_type_t lr_type = LR_TYPE_R15;
> +
> +  cache = FRAME_OBSTACK_ZALLOC (struct csky_unwind_cache);
> +  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
> +
> +  /* Assume there is no frame until proven otherwise.  */
> +  cache->framereg = sp_regnum;
> +
> +  cache->framesize = 0;
> +
> +  prev_pc = get_frame_pc (this_frame);
> +  block_addr = get_frame_address_in_block (this_frame);
> +  if (find_pc_partial_function (block_addr, NULL, &prologue_start,
> +                               &func_end) == 0)
> +    /* We couldn't find a function containing block_addr, so bail out
> +       and hope for the best.  */
> +    return cache;
> +
> +  /* Get the (function) symbol matching prologue_start.  */
> +  bl = block_for_pc (prologue_start);
> +  if (bl != NULL)
> +    func_size = bl->endaddr - bl->startaddr;
> +  else
> +    {
> +      struct bound_minimal_symbol msymbol
> +       = lookup_minimal_symbol_by_pc (prologue_start);
> +      if (msymbol.minsym != NULL)
> +       func_size = MSYMBOL_SIZE (msymbol.minsym);
> +    }
> +
> +  /* If FUNC_SIZE is 0 we may have a special-case use of lr
> +     e.g. exception or interrupt.  */
> +  if (func_size == 0)
> +    lr_type = csky_analyze_lr_type (gdbarch, prologue_start, func_end);
> +
> +  prologue_end = std::min (func_end, prev_pc);
> +
> +  /* Analyze the function prologue.  */
> +  csky_analyze_prologue (gdbarch, prologue_start, prologue_end,
> +                           func_end, this_frame, cache, lr_type);
> +
> +  /* gdbarch_sp_regnum contains the value and not the address.  */
> +  trad_frame_set_value (cache->saved_regs, sp_regnum, cache->prev_sp);
> +  return cache;
> +}
> +
> +/* Implement the unwind_pc gdbarch method.  */
> +
> +static CORE_ADDR
> +csky_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
> +{
> +  return frame_unwind_register_unsigned (next_frame, CSKY_PC_REGNUM);
> +}
> +
> +/* Implement the this_id function for the normal unwinder.  */
> +
> +static void
> +csky_frame_this_id (struct frame_info *this_frame,
> +                   void **this_prologue_cache, struct frame_id *this_id)
> +{
> +  struct csky_unwind_cache *cache;
> +  struct frame_id id;
> +
> +  if (*this_prologue_cache == NULL)
> +    *this_prologue_cache = csky_frame_unwind_cache (this_frame);
> +  cache = (struct csky_unwind_cache *) *this_prologue_cache;
> +
> +  /* This marks the outermost frame.  */
> +  if (cache->prev_sp == 0)
> +    return;
> +
> +  id = frame_id_build (cache->prev_sp, get_frame_func (this_frame));
> +  *this_id = id;
> +}
> +
> +/* Implement the prev_register function for the normal unwinder.  */
> +
> +static struct value *
> +csky_frame_prev_register (struct frame_info *this_frame,
> +                         void **this_prologue_cache, int regnum)
> +{
> +  struct csky_unwind_cache *cache;
> +
> +  if (*this_prologue_cache == NULL)
> +    *this_prologue_cache = csky_frame_unwind_cache (this_frame);
> +  cache = (struct csky_unwind_cache *) *this_prologue_cache;
> +
> +  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
> +                                      regnum);
> +}
> +
> +/* Data structures for the normal prologue-analysis-based
> +   unwinder.  */
> +
> +static const struct frame_unwind csky_unwind_cache = {
> +  NORMAL_FRAME,
> +  default_frame_unwind_stop_reason,
> +  csky_frame_this_id,
> +  csky_frame_prev_register,
> +  NULL,
> +  default_frame_sniffer,
> +  NULL,
> +  NULL
> +};
> +
> +
> +
> +static int
> +csky_stub_unwind_sniffer (const struct frame_unwind *self,
> +                        struct frame_info *this_frame,
> +                        void **this_prologue_cache)
> +{
> +  CORE_ADDR addr_in_block;
> +
> +  addr_in_block = get_frame_address_in_block (this_frame);
> +
> +  if (find_pc_partial_function (addr_in_block, NULL, NULL, NULL) == 0
> +      || in_plt_section (addr_in_block))
> +    return 1;
> +
> +  return 0;
> +}
> +
> +static struct csky_unwind_cache *
> +csky_make_stub_cache (struct frame_info *this_frame)
> +{
> +  struct csky_unwind_cache *cache;
> +
> +  cache = FRAME_OBSTACK_ZALLOC (struct csky_unwind_cache);
> +  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
> +  cache->prev_sp = get_frame_register_unsigned (this_frame,
> CSKY_SP_REGNUM);
> +
> +  return cache;
> +}
> +
> +static void
> +csky_stub_this_id (struct frame_info *this_frame,
> +                 void **this_cache,
> +                 struct frame_id *this_id)
> +{
> +  struct csky_unwind_cache *cache;
> +
> +  if (*this_cache == NULL)
> +    *this_cache = csky_make_stub_cache (this_frame);
> +  cache = (struct csky_unwind_cache *) *this_cache;
> +
> +  /* Our frame ID for a stub frame is the current SP and LR.  */
> +  *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
> +}
> +
> +static struct value *
> +csky_stub_prev_register (struct frame_info *this_frame,
> +                           void **this_cache,
> +                           int prev_regnum)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
> +  struct csky_unwind_cache *cache;
> +
> +  if (*this_cache == NULL)
> +    *this_cache = csky_make_stub_cache (this_frame);
> +  cache = (struct csky_unwind_cache *) *this_cache;
> +
> +  /* If we are asked to unwind the PC, then return the LR.  */
> +  if (prev_regnum == CSKY_PC_REGNUM)
> +    {
> +      CORE_ADDR lr;
> +
> +      lr = frame_unwind_register_unsigned (this_frame, CSKY_LR_REGNUM);
> +      return frame_unwind_got_constant (this_frame, prev_regnum, lr);
> +    }
> +
> +  if (prev_regnum == CSKY_SP_REGNUM)
> +    return frame_unwind_got_constant (this_frame, prev_regnum,
> cache->prev_sp);
> +
> +  return trad_frame_get_prev_register (this_frame, cache->saved_regs,
> +                                      prev_regnum);
> +}
> +
> +struct frame_unwind csky_stub_unwind = {
> +  NORMAL_FRAME,
> +  default_frame_unwind_stop_reason,
> +  csky_stub_this_id,
> +  csky_stub_prev_register,
> +  NULL,
> +  csky_stub_unwind_sniffer
> +};
> +
> +/* Implement the this_base, this_locals, and this_args hooks
> +   for the normal unwinder.  */
> +
> +static CORE_ADDR
> +csky_frame_base_address (struct frame_info *this_frame, void **this_cache)
> +{
> +  struct csky_unwind_cache *cache;
> +
> +  if (*this_cache == NULL)
> +    *this_cache = csky_frame_unwind_cache (this_frame);
> +  cache = (struct csky_unwind_cache *) *this_cache;
> +
> +  return cache->prev_sp - cache->framesize;
> +}
> +
> +static const struct frame_base csky_frame_base = {
> +  &csky_unwind_cache,
> +  csky_frame_base_address,
> +  csky_frame_base_address,
> +  csky_frame_base_address
> +};
> +
> +/* Implement the dummy_id gdbarch method.  The frame ID's base
> +   needs to match the TOS value saved by save_dummy_frame_tos,
> +   and the PC should match the dummy frame's breakpoint.  */
> +
> +static struct frame_id
> +csky_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
> +{
> +  unsigned int sp_regnum = CSKY_SP_REGNUM;
> +
> +  CORE_ADDR sp = get_frame_register_unsigned (this_frame, sp_regnum);
> +  return frame_id_build (sp, get_frame_pc (this_frame));
> +}
> +
> +/* Initialize register access method.  */
> +
> +static void
> +csky_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
> +                           struct dwarf2_frame_state_reg *reg,
> +                           struct frame_info *this_frame)
> +{
> +  if (regnum == gdbarch_pc_regnum (gdbarch))
> +    reg->how = DWARF2_FRAME_REG_RA;
> +  else if (regnum == gdbarch_sp_regnum (gdbarch))
> +    reg->how = DWARF2_FRAME_REG_CFA;
> +}
> +
> +/* Create csky register groups.  */
> +
> +static void
> +csky_init_reggroup ()
> +{
> +  cr_reggroup = reggroup_new ("cr", USER_REGGROUP);
> +  fr_reggroup = reggroup_new ("fr", USER_REGGROUP);
> +  vr_reggroup = reggroup_new ("vr", USER_REGGROUP);
> +  mmu_reggroup = reggroup_new ("mmu", USER_REGGROUP);
> +  prof_reggroup = reggroup_new ("profiling", USER_REGGROUP);
> +}
> +
> +/* Add register groups into reggroup list.  */
> +
> +static void
> +csky_add_reggroups (struct gdbarch *gdbarch)
> +{
> +  reggroup_add (gdbarch, all_reggroup);
> +  reggroup_add (gdbarch, general_reggroup);
> +  reggroup_add (gdbarch, cr_reggroup);
> +  reggroup_add (gdbarch, fr_reggroup);
> +  reggroup_add (gdbarch, vr_reggroup);
> +  reggroup_add (gdbarch, mmu_reggroup);
> +  reggroup_add (gdbarch, prof_reggroup);
> +}
> +
> +/* Return the groups that a CSKY register can be categorised into.  */
> +
> +static int
> +csky_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
> +                         struct reggroup *reggroup)
> +{
> +  int raw_p;
> +
> +  if (gdbarch_register_name (gdbarch, regnum) == NULL
> +      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
> +    return 0;
> +
> +  if (reggroup == all_reggroup)
> +    return 1;
> +
> +  raw_p = regnum < gdbarch_num_regs (gdbarch);
> +  if (reggroup == save_reggroup || reggroup == restore_reggroup)
> +    return raw_p;
> +
> +  if (((regnum >= CSKY_R0_REGNUM) && (regnum <= CSKY_R0_REGNUM + 31))
> +      && (reggroup == general_reggroup))
> +    return 1;
> +
> +  if (((regnum == CSKY_PC_REGNUM)
> +       || ((regnum >= CSKY_CR0_REGNUM)
> +          && (regnum <= CSKY_CR0_REGNUM + 30)))
> +      && (reggroup == cr_reggroup))
> +    return 2;
> +
> +  if ((((regnum >= CSKY_VR0_REGNUM) && (regnum <= CSKY_VR0_REGNUM + 15))
> +       || ((regnum >= CSKY_VCR0_REGNUM)
> +          && (regnum <= CSKY_VCR0_REGNUM + 2)))
> +      && (reggroup == vr_reggroup))
> +    return 3;
> +
> +  if (((regnum >= CSKY_MMU_REGNUM) && (regnum <= CSKY_MMU_REGNUM + 8))
> +      && (reggroup == mmu_reggroup))
> +    return 4;
> +
> +  if (((regnum >= CSKY_PROFCR_REGNUM)
> +       && (regnum <= CSKY_PROFCR_REGNUM + 48))
> +      && (reggroup == prof_reggroup))
> +    return 5;
> +
> +  if ((((regnum >= CSKY_FR0_REGNUM) && (regnum <= CSKY_FR0_REGNUM + 15))
> +       || ((regnum >= CSKY_VCR0_REGNUM) && (regnum <= CSKY_VCR0_REGNUM
> + 2)))
> +      && (reggroup == fr_reggroup))
> +    return 6;
> +
> +  return 0;
> +}
> +
> +/* Implement the dwarf2_reg_to_regnum gdbarch method.  */
> +
> +static int
> +csky_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int dw_reg)
> +{
> +  if (dw_reg < 0 || dw_reg >= CSKY_NUM_REGS)
> +    return -1;
> +  return dw_reg;
> +}
> +
> +/* Override interface for command: info register.  */
> +
> +static void
> +csky_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
> +                          struct frame_info *frame, int regnum, int all)
> +{
> +  /* Call default print_registers_info function.  */
> +  default_print_registers_info (gdbarch, file, frame, regnum, all);
> +
> +  /* For command: info register.  */
> +  if (regnum == -1 && all == 0)
> +    {
> +      default_print_registers_info (gdbarch, file, frame,
> +                                   CSKY_PC_REGNUM, 0);
> +      default_print_registers_info (gdbarch, file, frame,
> +                                   CSKY_EPC_REGNUM, 0);
> +      default_print_registers_info (gdbarch, file, frame,
> +                                   CSKY_CR0_REGNUM, 0);
> +      default_print_registers_info (gdbarch, file, frame,
> +                                   CSKY_EPSR_REGNUM, 0);
> +    }
> +  return;
> +}
> +
> +/* Initialize the current architecture based on INFO.  If possible,
> +   re-use an architecture from ARCHES, which is a list of
> +   architectures already created during this debugging session.
> +
> +   Called at program startup, when reading a core file, and when
> +   reading a binary file.  */
> +
> +static struct gdbarch *
> +csky_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
> +{
> +  struct gdbarch *gdbarch;
> +  struct gdbarch_tdep *tdep;
> +
> +  /* Find a candidate among the list of pre-declared architectures.  */
> +  arches = gdbarch_list_lookup_by_info (arches, &info);
> +  if (arches != NULL)
> +    return arches->gdbarch;
> +
> +  /* None found, create a new architecture from the information
> +     provided.  */
> +  tdep = XCNEW (struct gdbarch_tdep);
> +  gdbarch = gdbarch_alloc (&info, tdep);
> +
> +  /* Target data types.  */
> +  set_gdbarch_ptr_bit (gdbarch, 32);
> +  set_gdbarch_addr_bit (gdbarch, 32);
> +  set_gdbarch_short_bit (gdbarch, 16);
> +  set_gdbarch_int_bit (gdbarch, 32);
> +  set_gdbarch_long_bit (gdbarch, 32);
> +  set_gdbarch_long_long_bit (gdbarch, 64);
> +  set_gdbarch_float_bit (gdbarch, 32);
> +  set_gdbarch_double_bit (gdbarch, 64);
> +  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
> +  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
> +
> +  /* Information about the target architecture.  */
> +  set_gdbarch_return_value (gdbarch, csky_return_value);
> +  set_gdbarch_breakpoint_kind_from_pc (gdbarch,
> csky_breakpoint_kind_from_pc);
> +  set_gdbarch_sw_breakpoint_from_kind (gdbarch,
> csky_sw_breakpoint_from_kind);
> +
> +  /* Register architecture.  */
> +  set_gdbarch_num_regs (gdbarch, CSKY_NUM_REGS);
> +  set_gdbarch_pc_regnum (gdbarch, CSKY_PC_REGNUM);
> +  set_gdbarch_sp_regnum (gdbarch, CSKY_SP_REGNUM);
> +  set_gdbarch_register_name (gdbarch, csky_register_name);
> +  set_gdbarch_register_type (gdbarch, csky_register_type);
> +  set_gdbarch_read_pc (gdbarch, csky_read_pc);
> +  set_gdbarch_write_pc (gdbarch, csky_write_pc);
> +  set_gdbarch_print_registers_info (gdbarch, csky_print_registers_info);
> +  csky_add_reggroups (gdbarch);
> +  set_gdbarch_register_reggroup_p (gdbarch, csky_register_reggroup_p);
> +  set_gdbarch_stab_reg_to_regnum (gdbarch, csky_dwarf_reg_to_regnum);
> +  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, csky_dwarf_reg_to_regnum);
> +  dwarf2_frame_set_init_reg (gdbarch, csky_dwarf2_frame_init_reg);
> +
> +  /* Functions to analyze frames.  */
> +  frame_base_set_default (gdbarch, &csky_frame_base);
> +  set_gdbarch_skip_prologue (gdbarch, csky_skip_prologue);
> +  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
> +  set_gdbarch_frame_align (gdbarch, csky_frame_align);
> +  set_gdbarch_stack_frame_destroyed_p (gdbarch,
> csky_stack_frame_destroyed_p);
> +
> +  /* Functions to access frame data.  */
> +  set_gdbarch_unwind_pc (gdbarch, csky_unwind_pc);
> +  set_gdbarch_unwind_sp (gdbarch, csky_unwind_sp);
> +
> +  /* Functions handling dummy frames.  */
> +  set_gdbarch_push_dummy_call (gdbarch, csky_push_dummy_call);
> +  set_gdbarch_dummy_id (gdbarch, csky_dummy_id);
> +
> +  /* Frame unwinders.  Use DWARF debug info if available,
> +     otherwise use our own unwinder.  */
> +  dwarf2_append_unwinders (gdbarch);
> +  frame_unwind_append_unwinder (gdbarch, &csky_stub_unwind);
> +  frame_unwind_append_unwinder (gdbarch, &csky_unwind_cache);
> +
> +  /* Breakpoints.  */
> +  set_gdbarch_memory_insert_breakpoint (gdbarch,
> +                                       csky_memory_insert_breakpoint);
> +  set_gdbarch_memory_remove_breakpoint (gdbarch,
> +                                       csky_memory_remove_breakpoint);
> +
> +  /* Hook in ABI-specific overrides, if they have been registered.  */
> +  gdbarch_init_osabi (info, gdbarch);
> +
> +  /* Support simple overlay manager.  */
> +  set_gdbarch_overlay_update (gdbarch, simple_overlay_update);
> +  set_gdbarch_char_signed (gdbarch, 0);
> +  return gdbarch;
> +}
> +
> +void
> +_initialize_csky_tdep (void)
> +{
> +
> +  register_gdbarch_init (bfd_arch_csky, csky_gdbarch_init);
> +
> +  csky_init_reggroup ();
> +
> +  /* Allow debugging this file's internals.  */
> +  add_setshow_boolean_cmd ("csky", class_maintenance, &csky_debug,
> +                          _("Set C-Sky debugging."),
> +                          _("Show C-Sky debugging."),
> +                          _("When on, C-Sky specific debugging is enabled."),
> +                          NULL,
> +                          NULL,
> +                          &setdebuglist, &showdebuglist);
> +}
> diff --git a/gdb/csky-tdep.h b/gdb/csky-tdep.h
> new file mode 100644
> index 0000000000..49c29a9e1c
> --- /dev/null
> +++ b/gdb/csky-tdep.h
> @@ -0,0 +1,355 @@
> +/* Target-dependent code for the CSKY architecture, for GDB.
> +
> +   Copyright (C) 2010-2018 Free Software Foundation, 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/>.  */
> +
> +#ifndef CSKY_TDEP_H
> +#define CSKY_TDEP_H
> +
> +/* How to interpret the contents of the link register.  */
> +enum lr_type_t
> +{
> +  LR_TYPE_R15,
> +  LR_TYPE_EPC,
> +  LR_TYPE_FPC
> +};
> +
> +/* Target-dependent structure in gdbarch.  */
> +struct gdbarch_tdep
> +{
> +  /* This is Unused.  */
> +};
> +
> +/* Instruction sizes.  */
> +enum csky_insn_size_t
> +{
> +  CSKY_INSN_SIZE16 = 2,
> +  CSKY_INSN_SIZE32 = 4
> +};
> +
> +/* CSKY register numbers.  */
> +enum csky_regnum
> +{
> +  CSKY_R0_REGNUM = 0, /* General registers.  */
> +  CSKY_R15_REGNUM = 15,
> +  CSKY_PC_REGNUM = 72,
> +  CSKY_HI_REGNUM = 20,
> +  CSKY_LO_REGNUM = 21,
> +  CSKY_CR0_REGNUM = 89,
> +  CSKY_VBR_REGNUM = CSKY_CR0_REGNUM + 1,
> +  CSKY_EPSR_REGNUM = CSKY_CR0_REGNUM + 2,
> +  CSKY_FPSR_REGNUM = CSKY_CR0_REGNUM + 3,
> +  CSKY_EPC_REGNUM = CSKY_CR0_REGNUM + 4,
> +  CSKY_FPC_REGNUM = CSKY_CR0_REGNUM + 5,
> +
> +  /* Float register 0.  */
> +  CSKY_FR0_REGNUM = 40,
> +  CSKY_VCR0_REGNUM = 121,
> +  CSKY_MMU_REGNUM = 128,
> +  CSKY_PROFCR_REGNUM = 140,
> +  CSKY_PROFGR_REGNUM = 144,
> +  CSKY_FP_REGNUM = 8,
> +
> +  /* Vector register 0.  */
> +  CSKY_VR0_REGNUM = 56,
> +
> +  /* m32r calling convention.  */
> +  CSKY_SP_REGNUM = CSKY_R0_REGNUM + 14,
> +  CSKY_RET_REGNUM = CSKY_R0_REGNUM,
> +
> +  /* Argument registers.  */
> +  CSKY_ABI_A0_REGNUM = 0,
> +  CSKY_ABI_LAST_ARG_REGNUM = 3,
> +
> +  /* Link register, r15.  */
> +  CSKY_LR_REGNUM = CSKY_R15_REGNUM,
> +
> +  /* Processor status register, cr0.  */
> +  CSKY_PSR_REGNUM = CSKY_CR0_REGNUM,
> +
> +  CSKY_MAX_REGISTER_SIZE = 16,
> +  CSKY_MAX_REGS = 253
> +};
> +
> +/* ICE registers.  */
> +#define CSKY_CRBANK_NUM_REGS 32
> +
> +/* Number of processor registers w/o ICE registers.  */
> +#define CSKY_NUM_REGS (CSKY_MAX_REGS - CSKY_CRBANK_NUM_REGS)
> +
> +/* size.  */
> +#define CSKY_16_ST_SIZE(insn) (1 << ((insn & 0x1800) >> 11))
> +/* rx.  */
> +#define CSKY_16_ST_ADDR_REGNUM(insn) ((insn & 0x700) >> 8)
> +/* disp.  */
> +#define CSKY_16_ST_OFFSET(insn) ((insn & 0x1f) << ((insn & 0x1800) >> 11))
> +/* ry.  */
> +#define CSKY_16_ST_VAL_REGNUM(insn) ((insn & 0xe0) >> 5)
> +
> +/* st16.w rz, (sp, disp).  */
> +#define CSKY_16_IS_STWx0(insn) ((insn & 0xf800) == 0xb800)
> +#define CSKY_16_STWx0_VAL_REGNUM(insn) CSKY_16_ST_ADDR_REGNUM (insn)
> +
> +/* disp.  */
> +#define CSKY_16_STWx0_OFFSET(insn) \
> +  ((((insn & 0x700) >> 3) + (insn & 0x1f)) << 2)
> +
> +/* Check ld16 but not ld16 sp.  */
> +#define CSKY_16_IS_LD(insn) \
> +  (((insn & 0xe000) == 0x8000) && (insn & 0x1800) != 0x1800)
> +/* size.  */
> +#define CSKY_16_LD_SIZE(insn) CSKY_16_ST_SIZE (insn)
> +/* rx.  */
> +#define CSKY_16_LD_ADDR_REGNUM(insn) CSKY_16_ST_ADDR_REGNUM (insn)
> +/* disp.  */
> +#define CSKY_16_LD_OFFSET(insn) CSKY_16_ST_OFFSET (insn)
> +
> +/* ld16.w rz,(sp,disp).  */
> +#define CSKY_16_IS_LDWx0(insn) ((insn & 0xf800) == 0x9800)
> +/*disp.  */
> +#define CSKY_16_LDWx0_OFFSET(insn) CSKY_16_STWx0_OFFSET (insn)
> +
> +/* st32.b/h/w/d.  */
> +#define CSKY_32_IS_ST(insn) ((insn & 0xfc00c000) == 0xdc000000)
> +
> +/* size: b/h/w/d.  */
> +#define CSKY_32_ST_SIZE(insn) (1 << ((insn & 0x3000) >> 12))
> +/* rx.  */
> +#define CSKY_32_ST_ADDR_REGNUM(insn) ((insn & 0x001f0000) >> 16)
> +/* disp.  */
> +#define CSKY_32_ST_OFFSET(insn) ((insn & 0xfff) << ((insn & 0x3000) >> 12))
> +/* ry.  */
> +#define CSKY_32_ST_VAL_REGNUM(insn) ((insn & 0x03e00000) >> 21)
> +
> +/* stw ry, (sp, disp).  */
> +#define CSKY_32_IS_STWx0(insn) ((insn & 0xfc1ff000) == 0xdc0e2000)
> +
> +/* stm32 ry-rz, (rx).  */
> +#define CSKY_32_IS_STM(insn) ((insn & 0xfc00ffe0) == 0xd4001c20)
> +/* rx.  */
> +#define CSKY_32_STM_ADDR_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
> +/* Count of registers.  */
> +#define CSKY_32_STM_SIZE(insn) (insn & 0x1f)
> +/* ry.  */
> +#define CSKY_32_STM_VAL_REGNUM(insn) ((insn & 0x03e00000) >> 21)
> +/* stm32 ry-rz, (sp).  */
> +#define CSKY_32_IS_STMx0(insn) ((insn & 0xfc1fffe0) == 0xd40e1c20)
> +
> +/* str32.b/h/w rz, (rx, ry << offset).  */
> +#define CSKY_32_IS_STR(insn) \
> +  (((insn & 0xfc000000) == 0xd4000000) && !(CSKY_32_IS_STM (insn)))
> +/* rx.  */
> +#define CSKY_32_STR_X_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
> +/* ry.  */
> +#define CSKY_32_STR_Y_REGNUM(insn) ((insn >> 21) & 0x1f)
> +/* size: b/h/w.  */
> +#define CSKY_32_STR_SIZE(insn) (1 << ((insn & 0x0c00) >> 10))
> +/* imm (for rx + ry * imm).  */
> +#define CSKY_32_STR_OFFSET(insn) ((insn & 0x000003e0) >> 5)
> +
> +/* stex32.w rz, (rx, disp).  */
> +#define CSKY_32_IS_STEX(insn) ((insn & 0xfc00f000) == 0xdc007000)
> +/* rx.  */
> +#define CSKY_32_STEX_ADDR_REGNUM(insn) ((insn & 0x1f0000) >> 16)
> +/* disp.  */
> +#define CSKY_32_STEX_OFFSET(insn) ((insn & 0x0fff) << 2)
> +
> +/* ld.b/h/w.  */
> +#define CSKY_32_IS_LD(insn) ((insn & 0xfc00c000) == 0xd8000000)
> +/* size.  */
> +#define CSKY_32_LD_SIZE(insn) CSKY_32_ST_SIZE (insn)
> +/* rx.  */
> +#define CSKY_32_LD_ADDR_REGNUM(insn) CSKY_32_ST_ADDR_REGNUM (insn)
> +/* disp.  */
> +#define CSKY_32_LD_OFFSET(insn) CSKY_32_ST_OFFSET (insn)
> +#define CSKY_32_IS_LDM(insn) ((insn & 0xfc00ffe0) == 0xd0001c20)
> +/* rx.  */
> +#define CSKY_32_LDM_ADDR_REGNUM(insn) CSKY_32_STM_ADDR_REGNUM (insn)
> +/* Count of registers.  */
> +#define CSKY_32_LDM_SIZE(insn) CSKY_32_STM_SIZE (insn)
> +
> +/* ldr32.b/h/w rz, (rx, ry << offset).  */
> +#define CSKY_32_IS_LDR(insn) \
> +  (((insn & 0xfc00fe00) == 0xd0000000) && !(CSKY_32_IS_LDM (insn)))
> +/* rx.  */
> +#define CSKY_32_LDR_X_REGNUM(insn) CSKY_32_STR_X_REGNUM (insn)
> +/* ry.  */
> +#define CSKY_32_LDR_Y_REGNUM(insn) CSKY_32_STR_Y_REGNUM (insn)
> +/* size: b/h/w.  */
> +#define CSKY_32_LDR_SIZE(insn) CSKY_32_STR_SIZE (insn)
> +/* imm (for rx + ry*imm).  */
> +#define CSKY_32_LDR_OFFSET(insn) CSKY_32_STR_OFFSET (insn)
> +
> +#define CSKY_32_IS_LDEX(insn) ((insn & 0xfc00f000) == 0xd8007000)
> +/* rx.  */
> +#define CSKY_32_LDEX_ADDR_REGNUM(insn) CSKY_32_STEX_ADDR_REGNUM (insn)
> +/* disp.  */
> +#define CSKY_32_LDEX_OFFSET(insn) CSKY_32_STEX_OFFSET (insn)
> +
> +/* subi.sp sp, disp.  */
> +#define CSKY_16_IS_SUBI0(insn) ((insn & 0xfce0) == 0x1420)
> +/* disp.  */
> +#define CSKY_16_SUBI_IMM(insn) ((((insn & 0x300) >> 3) + (insn & 0x1f))
> << 2)
> +
> +/* subi32 sp,sp,oimm12.  */
> +#define CSKY_32_IS_SUBI0(insn) ((insn & 0xfffff000) == 0xe5ce1000)
> +/* oimm12.  */
> +#define CSKY_32_SUBI_IMM(insn) ((insn & 0xfff) + 1)
> +
> +/* push16.  */
> +#define CSKY_16_IS_PUSH(insn) ((insn & 0xffe0) == 0x14c0)
> +#define CSKY_16_IS_PUSH_R15(insn) ((insn & 0x10) == 0x10)
> +#define CSKY_16_PUSH_LIST1(insn) (insn & 0xf) /* r4 - r11.  */
> +
> +/* pop16.  */
> +#define CSKY_16_IS_POP(insn) ((insn & 0xffe0) == 0x1480)
> +#define CSKY_16_IS_POP_R15(insn) CSKY_16_IS_PUSH_R15 (insn)
> +#define CSKY_16_POP_LIST1(insn) CSKY_16_PUSH_LIST1 (insn) /* r4 - r11.  */
> +
> +/* push32.  */
> +#define CSKY_32_IS_PUSH(insn) ((insn & 0xfffffe00) == 0xebe00000)
> +#define CSKY_32_IS_PUSH_R29(insn) ((insn & 0x100) == 0x100)
> +#define CSKY_32_IS_PUSH_R15(insn) ((insn & 0x10) == 0x10)
> +#define CSKY_32_PUSH_LIST1(insn) (insn & 0xf)   /* r4 - r11.  */
> +#define CSKY_32_PUSH_LIST2(insn) ((insn & 0xe0) >> 5) /* r16 - r17.  */
> +
> +/* pop32.  */
> +#define CSKY_32_IS_POP(insn) ((insn & 0xfffffe00) == 0xebc00000)
> +#define CSKY_32_IS_POP_R29(insn) CSKY_32_IS_PUSH_R29 (insn)
> +#define CSKY_32_IS_POP_R15(insn) CSKY_32_IS_PUSH_R15 (insn)
> +#define CSKY_32_POP_LIST1(insn) CSKY_32_PUSH_LIST1 (insn) /* r4 - r11.  */
> +#define CSKY_32_POP_LIST2(insn) CSKY_32_PUSH_LIST2 (insn) /* r16 - r17.  */
> +
> +/* Adjust sp by r4(l0).  */
> +/* lrw r4, literal.  */
> +#define CSKY_16_IS_LRW4(x) (((x) &0xfce0) == 0x1080)
> +/* movi r4, imm8.  */
> +#define CSKY_16_IS_MOVI4(x) (((x) &0xff00) == 0x3400)
> +
> +/* addi r4, oimm8.  */
> +#define CSKY_16_IS_ADDI4(x) (((x) &0xff00) == 0x2400)
> +/* subi r4, oimm8.  */
> +#define CSKY_16_IS_SUBI4(x) (((x) &0xff00) == 0x2c00)
> +
> +/* nor16 r4, r4.  */
> +#define CSKY_16_IS_NOR4(x) ((x) == 0x6d12)
> +
> +/* lsli r4, r4, imm5.  */
> +#define CSKY_16_IS_LSLI4(x) (((x) &0xffe0) == 0x4480)
> +/* bseti r4, imm5.  */
> +#define CSKY_16_IS_BSETI4(x) (((x) &0xffe0) == 0x3ca0)
> +/* bclri r4, imm5.  */
> +#define CSKY_16_IS_BCLRI4(x) (((x) &0xffe0) == 0x3c80)
> +
> +/* subu sp, r4.  */
> +#define CSKY_16_IS_SUBU4(x) ((x) == 0x6392)
> +
> +#define CSKY_16_IS_R4_ADJUSTER(x) \
> +  (CSKY_16_IS_ADDI4 (x) || CSKY_16_IS_SUBI4 (x) || CSKY_16_IS_BSETI4 (x) \
> +   || CSKY_16_IS_BCLRI4 (x) || CSKY_16_IS_NOR4 (x) || CSKY_16_IS_LSLI4 (x))
> +
> +/* lrw r4, literal.  */
> +#define CSKY_32_IS_LRW4(x) (((x) &0xffff0000) == 0xea840000)
> +/* movi r4, imm16.  */
> +#define CSKY_32_IS_MOVI4(x) (((x) &0xffff0000) == 0xea040000)
> +/* movih r4, imm16.  */
> +#define CSKY_32_IS_MOVIH4(x) (((x) &0xffff0000) == 0xea240000)
> +/* bmaski r4, oimm5.  */
> +#define CSKY_32_IS_BMASKI4(x) (((x) &0xfc1fffff) == 0xc4005024)
> +/* addi r4, r4, oimm12.  */
> +#define CSKY_32_IS_ADDI4(x) (((x) &0xfffff000) == 0xe4840000)
> +/* subi r4, r4, oimm12.  */
> +#define CSKY_32_IS_SUBI4(x) (((x) &0xfffff000) == 0xe4810000)
> +
> +/* nor32 r4, r4, r4.  */
> +#define CSKY_32_IS_NOR4(x) ((x) == 0xc4842484)
> +/* rotli r4, r4, imm5.  */
> +#define CSKY_32_IS_ROTLI4(x) (((x) &0xfc1fffff) == 0xc4044904)
> +/* lsli r4, r4, imm5.  */
> +#define CSKY_32_IS_LISI4(x) (((x) &0xfc1fffff) == 0xc4044824)
> +/* bseti32 r4, r4, imm5.  */
> +#define CSKY_32_IS_BSETI4(x) (((x) &0xfc1fffff) == 0xc4042844)
> +/* bclri32 r4, r4, imm5.  */
> +#define CSKY_32_IS_BCLRI4(x) (((x) &0xfc1fffff) == 0xc4042824)
> +/* ixh r4, r4, r4.  */
> +#define CSKY_32_IS_IXH4(x) ((x) == 0xc4840824)
> +/* ixw r4, r4, r4.  */
> +#define CSKY_32_IS_IXW4(x) ((x) == 0xc4840844)
> +/* subu32 sp, sp, r4.  */
> +#define CSKY_32_IS_SUBU4(x) ((x) == 0xc48e008e)
> +
> +#define CSKY_32_IS_R4_ADJUSTER(x) \
> +  (CSKY_32_IS_ADDI4 (x) || CSKY_32_IS_SUBI4 (x) || CSKY_32_IS_ROTLI4 (x) \
> +   || CSKY_32_IS_IXH4 (x) || CSKY_32_IS_IXW4 (x) || CSKY_32_IS_NOR4 (x) \
> +   || CSKY_32_IS_BSETI4 (x) || CSKY_32_IS_BCLRI4 (x) ||
> CSKY_32_IS_LISI4 (x))
> +
> +#define CSKY_IS_R4_ADJUSTER(x)                                         \
> +  (CSKY_32_IS_R4_ADJUSTER (x) || CSKY_16_IS_R4_ADJUSTER (x))
> +#define CSKY_IS_SUBU4(x) (CSKY_32_IS_SUBU4 (x) || CSKY_16_IS_SUBU4 (x))
> +
> +/* mfcr rz, epsr.  */
> +#define CSKY_32_IS_MFCR_EPSR(insn) ((insn & 0xffffffe0) == 0xc0026020)
> +/* mfcr rz, fpsr.  */
> +#define CSKY_32_IS_MFCR_FPSR(insn) ((insn & 0xffffffe0) == 0xc0036020)
> +/* mfcr rz, epc.  */
> +#define CSKY_32_IS_MFCR_EPC(insn) ((insn & 0xffffffe0) == 0xc0046020)
> +/* mfcr rz, fpc.  */
> +#define CSKY_32_IS_MFCR_FPC(insn) ((insn & 0xffffffe0) == 0xc0056020)
> +
> +#define CSKY_32_IS_RTE(insn) (insn == 0xc0004020)
> +#define CSKY_32_IS_RFI(insn) (insn == 0xc0004420)
> +#define CSKY_32_IS_JMP(insn) ((insn & 0xffe0ffff) == 0xe8c00000)
> +#define CSKY_16_IS_JMP(insn) ((insn & 0xffc3) == 0x7800)
> +#define CSKY_32_IS_JMPI(insn) ((insn & 0xffff0000) == 0xeac00000)
> +#define CSKY_32_IS_JMPIX(insn) ((insn & 0xffe0fffc) == 0xe9e00000)
> +#define CSKY_16_IS_JMPIX(insn) ((insn & 0xf8fc) == 0x38e0)
> +
> +#define CSKY_16_IS_BR(insn) ((insn & 0xfc00) == 0x0400)
> +#define CSKY_32_IS_BR(insn) ((insn & 0xffff0000) == 0xe8000000)
> +#define CSKY_16_IS_MOV_FP_SP(insn) (insn == 0x6e3b)     /* mov r8, r14.  */
> +#define CSKY_32_IS_MOV_FP_SP(insn) (insn == 0xc40e4828) /* mov r8, r14.  */
> +#define CSKY_16_IS_MOV_SP_FP(insn) (insn == 0x6fa3)     /* mov r14, r8.  */
> +#define CSKY_32_INSN_MASK 0xc000
> +#define CSKY_BKPT_INSN 0x0
> +#define CSKY_NUM_GREGS 32
> +/* 32 general regs + 4.  */
> +#define CSKY_NUM_GREGS_SAVED_GREGS (CSKY_NUM_GREGS + 4)
> +
> +/* CSKY software bkpt write-mode.  */
> +#define CSKY_WR_BKPT_MODE 4
> +
> +/* Define insns for parse rt_sigframe.  */
> +/* There are three words(sig, pinfo, puc) before siginfo.  */
> +#define CSKY_SIGINFO_OFFSET 0xc
> +
> +/* Size of struct siginfo.  */
> +#define CSKY_SIGINFO_SIZE 0x80
> +
> +/* There are five words(uc_flags, uc_link, and three for uc_stack)
> +   in struct ucontext before sigcontext.  */
> +#define CSKY_UCONTEXT_SIGCONTEXT 0x14
> +
> +/* There is a word(sc_mask) before sc_usp.  */
> +#define CSKY_SIGCONTEXT_SC_USP 0x4
> +
> +/* There is a word(sc_usp) before sc_a0.  */
> +#define CSKY_SIGCONTEXT_SC_A0 0x4
> +
> +#define CSKY_MOVI_R7_173 0x00adea07
> +#define CSKY_TRAP_0 0x2020c000
> +
> +#endif
> --
> 2.11.0
>
>


--
Hafiz Abid Qadeer
Mentor Embedded/CodeSourcery
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Joel Brobecker
In reply to this post by Hafiz Abid Qadeer
> 2018-07-27  Jiangshuai Li  <[hidden email]>
>    Hafiz Abid Qadeer  <[hidden email]>
>    Don Breazeal  <[hidden email]>
>
> * csky-linux-tdep.c: New file.
> * csky-tdep.c: Likewise.
> * csky-tdep.h: Likewise.
> * Makefile.in (ALL_TARGET_OBS): Add csky-linux-tdep.o and
> csky-tdep.o.
> (HFILES_NO_SRCDIR): Add csky-tdep.h.
> (ALLDEPFILES): Add csky-linux-tdep.c and csky-tdep.c
> * configure.tgt: Add csky support.

This new version looks fine to me. Please feel free to push to master.

As for gdb-8.2-branch, this would be fine by me, on the basis that
this cannot affect the other already-supported targets.

--
Joel
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Hafiz Abid Qadeer
Hi Joel,
Thanks for the review.

On 26/08/18 10:28, Joel Brobecker wrote:

>> 2018-07-27  Jiangshuai Li  <[hidden email]>
>>    Hafiz Abid Qadeer  <[hidden email]>
>>    Don Breazeal  <[hidden email]>
>>
>> * csky-linux-tdep.c: New file.
>> * csky-tdep.c: Likewise.
>> * csky-tdep.h: Likewise.
>> * Makefile.in (ALL_TARGET_OBS): Add csky-linux-tdep.o and
>> csky-tdep.o.
>> (HFILES_NO_SRCDIR): Add csky-tdep.h.
>> (ALLDEPFILES): Add csky-linux-tdep.c and csky-tdep.c
>> * configure.tgt: Add csky support.
>
> This new version looks fine to me. Please feel free to push to master.
I have pushed it to master. The patch needed a few small changes after I
rebased it to latest.
https://sourceware.org/ml/gdb-cvs/2018-08/msg00122.html

>
> As for gdb-8.2-branch, this would be fine by me, on the basis that
> this cannot affect the other already-supported targets.
>
I decided to not put it in 8.2 as binutils ports went in after the 8.2
branch was cut.

I will update the MAINTAINERS file with the port maintainer info shortly.

Thanks,
--
Hafiz Abid Qadeer
Mentor Embedded/CodeSourcery
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Simon Marchi-4
In reply to this post by Hafiz Abid Qadeer
On 2018-07-25 6:54 a.m., Hafiz Abid Qadeer wrote:

> Add support for new target 'csky'.
>
> 2018-07-25  Jiangshuai Li  <[hidden email]>
>    Hafiz Abid Qadeer  <[hidden email]>
>    Don Breazeal  <[hidden email]>
>
> * csky-linux-tdep.c: New file.
> * csky-tdep.c: Likewise.
> * csky-tdep.h: Likewise.
> * Makefile.in (ALL_TARGET_OBS): Add csky-linux-tdep.o and
> csky-tdep.o.
> (HFILES_NO_SRCDIR): Add csky-tdep.h.
> (ALLDEPFILES): Add csky-linux-tdep.c and csky-tdep.c
> * configure.tgt: Add csky support.

Hi Hafiz,

I noticed the "cooked_read" selftest fails with c-sky (ever since the c-sky support was added):

(gdb) maintenance selftest cooked_read
Running selftest regcache::cooked_read_test.
...
Self test failed: arch csky: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
Self test failed: arch csky:ck510: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
Self test failed: arch csky:ck610: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
Self test failed: arch csky:ck801: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
Self test failed: arch csky:ck802: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
Self test failed: arch csky:ck803: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
Self test failed: arch csky:ck807: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
Self test failed: arch csky:ck810: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
Self test failed: arch csky:any: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
...
Self test failed: self-test failed at /home/simark/src/binutils-gdb/gdb/selftest-arch.c:86
Ran 1 unit tests, 1 failed

Could you take a look?

Thanks,

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Hafiz Abid Qadeer
On 20/10/18 19:55, Simon Marchi wrote:
> On 2018-07-25 6:54 a.m., Hafiz Abid Qadeer wrote:

> Hi Hafiz,
>
> I noticed the "cooked_read" selftest fails with c-sky (ever since the c-sky support was added):
>
> (gdb) maintenance selftest cooked_read
> Running selftest regcache::cooked_read_test.
> ...
> Self test failed: arch csky: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> Self test failed: arch csky:ck510: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> Self test failed: arch csky:ck610: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> Self test failed: arch csky:ck801: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> Self test failed: arch csky:ck802: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> Self test failed: arch csky:ck803: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> Self test failed: arch csky:ck807: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> Self test failed: arch csky:ck810: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> Self test failed: arch csky:any: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
> ...
> Self test failed: self-test failed at /home/simark/src/binutils-gdb/gdb/selftest-arch.c:86
> Ran 1 unit tests, 1 failed
>
> Could you take a look?
Hi Simon,
Thanks for letting me know. I am traveling at the moment. Will take a
look at it when I am back in a few days.

Thanks,
Abid


--
Hafiz Abid Qadeer
Mentor Embedded/CodeSourcery
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Simon Marchi-4
On 2018-10-20 11:04 p.m., Hafiz Abid Qadeer wrote:

> On 20/10/18 19:55, Simon Marchi wrote:
>> On 2018-07-25 6:54 a.m., Hafiz Abid Qadeer wrote:
>
>> Hi Hafiz,
>>
>> I noticed the "cooked_read" selftest fails with c-sky (ever since the c-sky support was added):
>>
>> (gdb) maintenance selftest cooked_read
>> Running selftest regcache::cooked_read_test.
>> ...
>> Self test failed: arch csky: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> Self test failed: arch csky:ck510: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> Self test failed: arch csky:ck610: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> Self test failed: arch csky:ck801: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> Self test failed: arch csky:ck802: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> Self test failed: arch csky:ck803: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> Self test failed: arch csky:ck807: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> Self test failed: arch csky:ck810: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> Self test failed: arch csky:any: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>> ...
>> Self test failed: self-test failed at /home/simark/src/binutils-gdb/gdb/selftest-arch.c:86
>> Ran 1 unit tests, 1 failed
>>
>> Could you take a look?
> Hi Simon,
> Thanks for letting me know. I am traveling at the moment. Will take a
> look at it when I am back in a few days.

Ok, thanks!

A quick investigation shows it's because some raw registers are not in the
save reggroup.  So csky should probably be added to that big if in the test:

          if (bfd_arch == bfd_arch_frv || bfd_arch == bfd_arch_h8300
              || bfd_arch == bfd_arch_m32c || bfd_arch == bfd_arch_sh
              || bfd_arch == bfd_arch_alpha || bfd_arch == bfd_arch_v850
              || bfd_arch == bfd_arch_msp430 || bfd_arch == bfd_arch_mep
              || bfd_arch == bfd_arch_mips || bfd_arch == bfd_arch_v850_rh850
              || bfd_arch == bfd_arch_tic6x || bfd_arch == bfd_arch_mn10300
              || bfd_arch == bfd_arch_rl78 || bfd_arch == bfd_arch_score
              || bfd_arch == bfd_arch_riscv)
            {
              /* Raw registers.  If raw registers are not in save_reggroup,
                 their status are unknown.  */
              if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup))
                SELF_CHECK (status == REG_VALID);
              else
                SELF_CHECK (status == REG_UNKNOWN);
            }
          else
            SELF_CHECK (status == REG_VALID);

But I'm tempted to replace all of that with simply;

          /* Raw registers.  If raw registers are not in save_reggroup,
             their status are unknown.  */
          if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup))
            SELF_CHECK (status == REG_VALID);
          else
            SELF_CHECK (status == REG_UNKNOWN);

We won't have to maintain this big list, and I don't think we lose any testing
coverage/safety.  For architectures for which all raw registers are in the
save_reggroup (all arches not listed above), we will still always assert that
status == REG_VALID.

I'll let you take a look when you have time.

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Hafiz Abid Qadeer
On 21/10/18 04:22, Simon Marchi wrote:

> On 2018-10-20 11:04 p.m., Hafiz Abid Qadeer wrote:
>> On 20/10/18 19:55, Simon Marchi wrote:
>>> On 2018-07-25 6:54 a.m., Hafiz Abid Qadeer wrote:
>>
>>> Hi Hafiz,
>>>
>>> I noticed the "cooked_read" selftest fails with c-sky (ever since the c-sky support was added):
>>>
>>> (gdb) maintenance selftest cooked_read
>>> Running selftest regcache::cooked_read_test.
>>> ...
>>> Self test failed: arch csky: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> Self test failed: arch csky:ck510: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> Self test failed: arch csky:ck610: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> Self test failed: arch csky:ck801: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> Self test failed: arch csky:ck802: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> Self test failed: arch csky:ck803: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> Self test failed: arch csky:ck807: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> Self test failed: arch csky:ck810: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> Self test failed: arch csky:any: self-test failed at /home/simark/src/binutils-gdb/gdb/regcache.c:1697
>>> ...
>>> Self test failed: self-test failed at /home/simark/src/binutils-gdb/gdb/selftest-arch.c:86
>>> Ran 1 unit tests, 1 failed
>>>
>>> Could you take a look?
>> Hi Simon,
>> Thanks for letting me know. I am traveling at the moment. Will take a
>> look at it when I am back in a few days.
>
> Ok, thanks!
>
> A quick investigation shows it's because some raw registers are not in the
> save reggroup.  So csky should probably be added to that big if in the test:
>
>  if (bfd_arch == bfd_arch_frv || bfd_arch == bfd_arch_h8300
>      || bfd_arch == bfd_arch_m32c || bfd_arch == bfd_arch_sh
>      || bfd_arch == bfd_arch_alpha || bfd_arch == bfd_arch_v850
>      || bfd_arch == bfd_arch_msp430 || bfd_arch == bfd_arch_mep
>      || bfd_arch == bfd_arch_mips || bfd_arch == bfd_arch_v850_rh850
>      || bfd_arch == bfd_arch_tic6x || bfd_arch == bfd_arch_mn10300
>      || bfd_arch == bfd_arch_rl78 || bfd_arch == bfd_arch_score
>      || bfd_arch == bfd_arch_riscv)
>    {
>      /* Raw registers.  If raw registers are not in save_reggroup,
> their status are unknown.  */
>      if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup))
> SELF_CHECK (status == REG_VALID);
>      else
> SELF_CHECK (status == REG_UNKNOWN);
>    }
>  else
>    SELF_CHECK (status == REG_VALID);
>

When I was reviewing the test results for csky, I saw this fail in
unittest.exp and fixed it by adding csky to the big if list as you
mentioned above. Somehow I missed that patch when upstreaming the port.
So if you are happy with that change then I will push it.

> But I'm tempted to replace all of that with simply;
>
>  /* Raw registers.  If raw registers are not in save_reggroup,
>     their status are unknown.  */
>  if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup))
>    SELF_CHECK (status == REG_VALID);
>  else
>    SELF_CHECK (status == REG_UNKNOWN);
>
> We won't have to maintain this big list, and I don't think we lose any testing
> coverage/safety.  For architectures for which all raw registers are in the
> save_reggroup (all arches not listed above), we will still always assert that
> status == REG_VALID.

I have not looked at this code much but your suggestion makes sense to me.

Regards,
--
Hafiz Abid Qadeer
Mentor Embedded/CodeSourcery
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Simon Marchi-4
On 2018-10-23 08:48, Hafiz Abid Qadeer wrote:

>> A quick investigation shows it's because some raw registers are not in
>> the
>> save reggroup.  So csky should probably be added to that big if in the
>> test:
>>
>>  if (bfd_arch == bfd_arch_frv || bfd_arch == bfd_arch_h8300
>>      || bfd_arch == bfd_arch_m32c || bfd_arch == bfd_arch_sh
>>      || bfd_arch == bfd_arch_alpha || bfd_arch == bfd_arch_v850
>>      || bfd_arch == bfd_arch_msp430 || bfd_arch == bfd_arch_mep
>>      || bfd_arch == bfd_arch_mips || bfd_arch == bfd_arch_v850_rh850
>>      || bfd_arch == bfd_arch_tic6x || bfd_arch == bfd_arch_mn10300
>>      || bfd_arch == bfd_arch_rl78 || bfd_arch == bfd_arch_score
>>      || bfd_arch == bfd_arch_riscv)
>>    {
>>      /* Raw registers.  If raw registers are not in save_reggroup,
>> their status are unknown.  */
>>      if (gdbarch_register_reggroup_p (gdbarch, regnum,
>> save_reggroup))
>> SELF_CHECK (status == REG_VALID);
>>      else
>> SELF_CHECK (status == REG_UNKNOWN);
>>    }
>>  else
>>    SELF_CHECK (status == REG_VALID);
>>
>
> When I was reviewing the test results for csky, I saw this fail in
> unittest.exp and fixed it by adding csky to the big if list as you
> mentioned above. Somehow I missed that patch when upstreaming the port.
> So if you are happy with that change then I will push it.

Yes please, consider it pre-approved.  We can take a look at removing
the big list laster.

Thanks,

Simon
Reply | Threaded
Open this post in threaded view
|

Re: [1/2] C-SKY Port

Hafiz Abid Qadeer
On 23/10/18 17:42, Simon Marchi wrote:

> On 2018-10-23 08:48, Hafiz Abid Qadeer wrote:
>>> A quick investigation shows it's because some raw registers are not
>>> in the
>>> save reggroup.  So csky should probably be added to that big if in
>>> the test:
>>>
>>>       if (bfd_arch == bfd_arch_frv || bfd_arch == bfd_arch_h8300
>>>           || bfd_arch == bfd_arch_m32c || bfd_arch == bfd_arch_sh
>>>           || bfd_arch == bfd_arch_alpha || bfd_arch == bfd_arch_v850
>>>           || bfd_arch == bfd_arch_msp430 || bfd_arch == bfd_arch_mep
>>>           || bfd_arch == bfd_arch_mips || bfd_arch ==
>>> bfd_arch_v850_rh850
>>>           || bfd_arch == bfd_arch_tic6x || bfd_arch == bfd_arch_mn10300
>>>           || bfd_arch == bfd_arch_rl78 || bfd_arch == bfd_arch_score
>>>           || bfd_arch == bfd_arch_riscv)
>>>         {
>>>           /* Raw registers.  If raw registers are not in save_reggroup,
>>>          their status are unknown.  */
>>>           if (gdbarch_register_reggroup_p (gdbarch, regnum,
>>> save_reggroup))
>>>         SELF_CHECK (status == REG_VALID);
>>>           else
>>>         SELF_CHECK (status == REG_UNKNOWN);
>>>         }
>>>       else
>>>         SELF_CHECK (status == REG_VALID);
>>>
>>
>> When I was reviewing the test results for csky, I saw this fail in
>> unittest.exp and fixed it by adding csky to the big if list as you
>> mentioned above. Somehow I missed that patch when upstreaming the port.
>> So if you are happy with that change then I will push it.
>
> Yes please, consider it pre-approved.  We can take a look at removing
> the big list laster.

I pushed the following patch.

gdb/ChangeLog:
2018-10-23  Hafiz Abid Qadeer  <[hidden email]>

        * regcache.c (cooked_read_test): Add CSKY to the list of
        architectures with a save_reggroup

--
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 38ad7ba3f1..946035ae67 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -1679,7 +1679,7 @@ cooked_read_test (struct gdbarch *gdbarch)
       || bfd_arch == bfd_arch_mips || bfd_arch == bfd_arch_v850_rh850
       || bfd_arch == bfd_arch_tic6x || bfd_arch == bfd_arch_mn10300
       || bfd_arch == bfd_arch_rl78 || bfd_arch == bfd_arch_score
-      || bfd_arch == bfd_arch_riscv)
+      || bfd_arch == bfd_arch_riscv || bfd_arch == bfd_arch_csky)
     {
       /* Raw registers.  If raw registers are not in save_reggroup,
  their status are unknown.  */


Thanks,

--
Hafiz Abid Qadeer
Mentor Embedded/CodeSourcery