From 207ef96a198bfdabf3efa6ad3d12e6fddbda2964 Mon Sep 17 00:00:00 2001
From: Ajit Kumar Agarwal <ajitkum@xhdspdgnu.(none)>
Date: Wed, 10 Sep 2014 15:19:54 +0530
Subject: [PATCH] [Patch, microblaze]: Port of Linux gdbserver

This patch is the port of Linux gdbserver.

ChangeLog:
2014-10-09  Ajit Agarwal  <ajitkum@xilinx.com>

	* microblaze-tdep.h (MICROBLAZE_BREAKPOINT): New Macro.
	(MICROBLAZE_BREAKPOINT_LE): New Macro.
	* microblaze-linux-tdep.c
	(microblaze_linux_memory_remove_breakpoint): Use of
	set_gdbarch_fetch_tls_load_module_address, do_cleanup.
	* configure.host (microblaze): New.
	(microblaze*-*-linux*): New.
	* configure.tgt (build_gdbserver): New Definition.
	* gdbserver/Makefile.in (microblaze-linux.c): New target.
	* gdbserver/configure.srv (microblaze*-*-linux*): New target.
	* gdbserver/linux-microblaze-low.c: New file.

Signed-off-by:Ajit Agarwal ajitkum@xilinx.com
---
 gdb/configure.host                   |    3 +
 gdb/configure.tgt                    |    1 +
 gdb/gdbserver/Makefile.in            |    4 +
 gdb/gdbserver/configure.srv          |    6 +
 gdb/gdbserver/linux-microblaze-low.c |  236 ++++++++++++++++++++++++++++++++++
 gdb/microblaze-linux-tdep.c          |   11 ++
 gdb/microblaze-tdep.h                |    4 +-
 7 files changed, 264 insertions(+), 1 deletions(-)
 create mode 100644 gdb/gdbserver/linux-microblaze-low.c

diff --git a/gdb/configure.host b/gdb/configure.host
index 15a8288..6f02ddd 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -59,6 +59,7 @@ i[34567]86*)		gdb_host_cpu=i386 ;;
 m68*)			gdb_host_cpu=m68k ;;
 m88*)			gdb_host_cpu=m88k ;;
 mips*)			gdb_host_cpu=mips ;;
+microblaze*)            gdb_host_cpu=microblaze ;;
 powerpc* | rs6000)	gdb_host_cpu=powerpc ;;
 sparcv9 | sparc64)	gdb_host_cpu=sparc ;;
 s390*)			gdb_host_cpu=s390 ;;
@@ -133,6 +134,8 @@ mips*-*-netbsd* | mips*-*-knetbsd*-gnu)
 			gdb_host=nbsd ;;
 mips64*-*-openbsd*)	gdb_host=obsd64 ;;
 
+microblaze*-*linux*)    gdb_host=linux ;;
+
 powerpc-*-aix* | rs6000-*-* | powerpc64-*-aix*)
 			gdb_host=aix ;;
 powerpc*-*-freebsd*)	gdb_host=fbsd ;;
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 01311b2..e4894da 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -343,6 +343,7 @@ microblaze*-linux-*|microblaze*-*-linux*)
 	gdb_target_obs="microblaze-tdep.o microblaze-linux-tdep.o microblaze-rom.o \
 			monitor.o dsrec.o solib-svr4.o symfile-mem.o linux-tdep.o"
 	gdb_sim=../sim/microblaze/libsim.a
+        build_gdbserver=yes
 	;;
 microblaze*-*-*)
 	# Target: Xilinx MicroBlaze running standalone
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1447e61..b2a01f5 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -153,6 +153,7 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/linux-ia64-low.c $(srcdir)/linux-low.c \
 	$(srcdir)/linux-m32r-low.c \
 	$(srcdir)/linux-m68k-low.c $(srcdir)/linux-mips-low.c \
+        $(srcdir)/linux-microblaze-low.c \
 	$(srcdir)/linux-nios2-low.c \
 	$(srcdir)/linux-ppc-low.c \
 	$(srcdir)/linux-s390-low.c \
@@ -364,6 +365,7 @@ clean:
 	rm -f amd64-mpx.c amd64-mpx-linux.c
 	rm -f amd64-avx512.c amd64-avx512-linux.c
 	rm -f i386-mmx.c i386-mmx-linux.c
+        rm -f microblaze-linux.c
 	rm -f x32.c x32-linux.c
 	rm -f x32-avx.c x32-avx-linux.c
 	rm -f x32-avx512.c x32-avx512-linux.c
@@ -634,6 +636,8 @@ mips64-linux.c : $(srcdir)/../regformats/mips64-linux.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/mips64-linux.dat mips64-linux.c
 mips64-dsp-linux.c : $(srcdir)/../regformats/mips64-dsp-linux.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/mips64-dsp-linux.dat mips64-dsp-linux.c
+microblaze-linux.c : $(srcdir)/../regformats/microblaze-with-stack-protect.dat $(regdat_sh)
+        $(SHELL) $(regdat_sh) $(srcdir)/../regformats/microblaze-with-stack-protect.dat  microblaze-linux.c
 nios2-linux.c :	$(srcdir)/../regformats/nios2-linux.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/nios2-linux.dat nios2-linux.c
 powerpc-32.c : $(srcdir)/../regformats/rs6000/powerpc-32.dat $(regdat_sh)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 679fc9f..16e44ee 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -194,6 +194,12 @@ case "${target}" in
 			srv_linux_usrregs=yes
 			srv_linux_thread_db=yes
 			;;
+  microblaze*-*-linux*) srv_regobj=microblaze-linux.o
+                        srv_tgtobj="$srv_linux_obj linux-microblaze-low.o"
+                        srv_linux_usrregs=yes
+                        srv_linux_regsets=yes
+                        srv_linux_thread_db=yes
+                        ;;
   nios2*-*-linux*)	srv_regobj="nios2-linux.o"
 			srv_tgtobj="$srv_linux_obj linux-nios2-low.o"
 			srv_xmlfiles="nios2-linux.xml"
diff --git a/gdb/gdbserver/linux-microblaze-low.c b/gdb/gdbserver/linux-microblaze-low.c
new file mode 100644
index 0000000..ac6b998
--- /dev/null
+++ b/gdb/gdbserver/linux-microblaze-low.c
@@ -0,0 +1,236 @@
+/* GNU/Linux/Microblaze specific low level interface, for the remote server for 
+   GDB. 
+   Copyright (C) 2014 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/>.  */ 
+ 
+#include "server.h"
+#include "linux-low.h"
+#include <asm/ptrace.h>
+#include <sys/procfs.h>
+ 
+#include "gdb_proc_service.h"
+
+void init_registers_microblaze_with_stack_protect (void);
+extern const struct target_desc *tdesc_microblaze_with_stack_protect;
+
+static int microblaze_regmap[] = {
+  PT_GPR(0),     PT_GPR(1),     PT_GPR(2),     PT_GPR(3),
+  PT_GPR(4),     PT_GPR(5),     PT_GPR(6),     PT_GPR(7),
+  PT_GPR(8),     PT_GPR(9),     PT_GPR(10),    PT_GPR(11),
+  PT_GPR(12),    PT_GPR(13),    PT_GPR(14),    PT_GPR(15),
+  PT_GPR(16),    PT_GPR(17),    PT_GPR(18),    PT_GPR(19),
+  PT_GPR(20),    PT_GPR(21),    PT_GPR(22),    PT_GPR(23),
+  PT_GPR(24),    PT_GPR(25),    PT_GPR(26),    PT_GPR(27),
+  PT_GPR(28),    PT_GPR(29),    PT_GPR(30),    PT_GPR(31),
+  PT_PC,         PT_MSR,        PT_EAR,        PT_ESR,
+  PT_FSR,        PT_BTR,        PT_PVR0,       PT_PVR1,
+  PT_PVR2,       PT_PVR3,       PT_PVR4,       PT_PVR5,
+  PT_PVR6,       PT_PVR7,       PT_PVR8,       PT_PVR9,
+  PT_PVR10,      PT_PVR11,      PT_EDR,        PT_PID,        
+  PT_ZPR,        PT_TLBX,       PT_TLBSX,      PT_TLBLO,
+  PT_TLBHI,      PT_SLR,        PT_SHR
+};
+
+#define microblaze_num_regs (sizeof microblaze_regmap / sizeof microblaze_regmap[0])
+ 
+static int
+microblaze_cannot_store_register (int regno)
+{
+  if (microblaze_regmap[regno] == -1 || regno == 0)
+    return 1;
+ 
+    return 0;
+}
+ 
+static int
+microblaze_cannot_fetch_register (int regno)
+{
+  return 0;
+}
+ 
+static CORE_ADDR
+microblaze_get_pc (struct regcache *regcache)
+{
+  unsigned long pc;
+  collect_register_by_name (regcache, "pc", &pc);
+  return (CORE_ADDR) (pc);
+}
+ 
+static void 
+microblaze_set_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  unsigned long newpc = pc;
+  supply_register_by_name (regcache, "pc", &newpc);
+}
+ 
+/* dbtrap insn */
+/* brki r16, 0x18; */
+ 
+static const unsigned long microblaze_breakpoint = 0xba0c0018;
+
+#define microblaze_breakpoint_len 4
+ 
+static int
+microblaze_breakpoint_at (CORE_ADDR where)
+{
+  unsigned long insn;
+  (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
+
+  if (insn == microblaze_breakpoint)
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+      one.  */
+   return 0;
+}
+ 
+static CORE_ADDR
+microblaze_reinsert_addr (struct regcache *regcache)
+{
+  unsigned long pc;
+  collect_register_by_name (regcache, "r15", &pc);
+  return pc;
+}
+ 
+#ifdef HAVE_PTRACE_GETREGS
+ 
+static void
+microblaze_collect_ptrace_register (struct regcache *regcache, int regno, char *buf)
+{
+  int size = register_size (regcache->tdesc, regno);
+  memset (buf, 0, sizeof (long));
+
+  if (size < sizeof (long))
+    collect_register (regcache, regno, buf + sizeof (long) - size);
+  else
+    collect_register (regcache, regno, buf);
+}
+ 
+static void
+microblaze_supply_ptrace_register (struct regcache *regcache,
+			    int regno, const char *buf)
+{
+  int i;
+  int size = register_size (regcache->tdesc, regno);
+
+  if (regno == 0)
+    {
+      unsigned long regbuf_0 = 0;
+      /* Clobbering r0 so that it is always 0 as enforced by hardware.  */ 
+      supply_register (regcache, regno, (const char*)&regbuf_0); 
+  } else {
+      if (size < sizeof (long))
+        supply_register (regcache, regno, buf + sizeof (long) - size);
+      else
+        supply_register (regcache, regno, buf);
+  }
+}
+ 
+/* Provide only a fill function for the general register set.  ps_lgetregs
+   will use this for NPTL support.  */
+ 
+static void microblaze_fill_gregset (struct regcache *regcache, void *buf)
+{
+  int i;
+ 
+  for (i = 0; i < microblaze_num_regs; i++) 
+    microblaze_collect_ptrace_register (regcache, i, (char *) buf + microblaze_regmap[i]);
+}
+ 
+static void
+microblaze_store_gregset (struct regcache *regcache, const void *buf)
+{
+  int i;
+  for (i = 0; i < microblaze_num_regs; i++)
+    supply_register (regcache, i, (char *) buf + microblaze_regmap[i]);
+}
+ 
+#endif /* HAVE_PTRACE_GETREGS */
+
+static struct regset_info microblaze_regsets[] = {
+#ifdef HAVE_PTRACE_GETREGS
+  { PTRACE_GETREGS, PTRACE_SETREGS, 0, 36 * sizeof (elf_gregset_t), GENERAL_REGS, microblaze_fill_gregset, microblaze_store_gregset },
+  { 0, 0, 0, -1, -1, NULL, NULL },
+#endif /* HAVE_PTRACE_GETREGS */
+  { 0, 0, 0, -1, -1, NULL, NULL }
+}; 
+
+static struct regsets_info microblaze_regsets_info = {
+ 
+  microblaze_regsets, /* regsets */
+  0, /* num_regsets */
+  NULL, /* disabled_regsets */
+};
+ 
+static struct usrregs_info microblaze_usrregs_info =
+{ 
+   microblaze_num_regs,
+   microblaze_regmap,
+};
+ 
+static struct regs_info regs_info =
+{
+  NULL, /* regset_bitmap */
+  &microblaze_usrregs_info,
+  &microblaze_regsets_info 
+};
+ 
+static const struct regs_info *
+microblaze_regs_info (void)
+{
+  return &regs_info;
+}
+
+static void
+microblaze_arch_setup (void)
+{
+  current_process ()->tdesc = tdesc_microblaze_with_stack_protect;
+}
+
+struct linux_target_ops the_low_target = {
+  microblaze_arch_setup,
+  microblaze_regs_info,
+  microblaze_cannot_fetch_register,
+  microblaze_cannot_store_register,
+  NULL, /* fetch_register */
+  microblaze_get_pc,
+  microblaze_set_pc,
+  (const unsigned char *) &microblaze_breakpoint,
+  microblaze_breakpoint_len,
+  microblaze_reinsert_addr,
+  0,
+  microblaze_breakpoint_at,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  microblaze_collect_ptrace_register,
+  microblaze_supply_ptrace_register,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+void
+initialize_low_arch (void)
+{
+  init_registers_microblaze_with_stack_protect ();
+
+  initialize_regsets_info (&microblaze_regsets_info);
+}
diff --git a/gdb/microblaze-linux-tdep.c b/gdb/microblaze-linux-tdep.c
index 8d360eb..af4d31c 100644
--- a/gdb/microblaze-linux-tdep.c
+++ b/gdb/microblaze-linux-tdep.c
@@ -46,12 +46,16 @@ microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
   int val;
   int bplen;
   gdb_byte old_contents[BREAKPOINT_MAX];
+  struct cleanup *cleanup;
 
   /* Determine appropriate breakpoint contents and size for this address.  */
   bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
   if (bp == NULL)
     error (_("Software breakpoints not implemented for this target."));
 
+  /* Make sure we see the memory breakpoints.  */ 
+  cleanup = make_show_memory_breakpoints_cleanup (1); 
+
   val = target_read_memory (addr, old_contents, bplen);
 
   /* If our breakpoint is no longer at the address, this means that the
@@ -60,6 +64,7 @@ microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
   if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
     val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
 
+  do_cleanups (cleanup);
   return val;
 }
 
@@ -135,6 +140,12 @@ microblaze_linux_init_abi (struct gdbarch_info info,
   /* Trampolines.  */
   tramp_frame_prepend_unwinder (gdbarch,
 				&microblaze_linux_sighandler_tramp_frame);
+  
+   /* Enable TLS support.  */ 
+   set_gdbarch_fetch_tls_load_module_address (gdbarch, 
+                                              svr4_fetch_objfile_link_map); 
+    
+
 }
 
 /* -Wmissing-prototypes */
diff --git a/gdb/microblaze-tdep.h b/gdb/microblaze-tdep.h
index ba240e9..574197c 100644
--- a/gdb/microblaze-tdep.h
+++ b/gdb/microblaze-tdep.h
@@ -117,6 +117,8 @@ struct microblaze_frame_cache
 
 /* MICROBLAZE_BREAKPOINT defines the breakpoint that should be used.
    Only used for native debugging.  */
-#define MICROBLAZE_BREAKPOINT {0xb9, 0xcc, 0x00, 0x60}
+#define MICROBLAZE_BREAKPOINT {0xba, 0x0c, 0x00, 0x18} 
+#define MICROBLAZE_BREAKPOINT_LE {0x18, 0x00, 0x0c, 0xba 
+
 
 #endif /* microblaze-tdep.h */
-- 
1.7.1

