summaryrefslogtreecommitdiff
path: root/package/gdb
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2014-03-28 07:30:20 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2014-03-28 07:30:20 +0100
commit12c9d74bb923174117e28186e4a7698e623803a2 (patch)
tree5e65f724ddcf7a82b56f915cc4d09ba2b47a65b7 /package/gdb
parenta47f1c5bff1fab6d622ac3d440f62cb4f6cdcc3a (diff)
add support for microblaze native debugging from xilinx-gdb git repo
Diffstat (limited to 'package/gdb')
-rw-r--r--package/gdb/patches/microblaze.patch1842
1 files changed, 1842 insertions, 0 deletions
diff --git a/package/gdb/patches/microblaze.patch b/package/gdb/patches/microblaze.patch
new file mode 100644
index 000000000..ce3f9b35b
--- /dev/null
+++ b/package/gdb/patches/microblaze.patch
@@ -0,0 +1,1842 @@
+diff -Nur gdb-7.7.orig/bfd/bfd-in2.h gdb-7.7/bfd/bfd-in2.h
+--- gdb-7.7.orig/bfd/bfd-in2.h 2014-02-06 03:21:29.000000000 +0100
++++ gdb-7.7/bfd/bfd-in2.h 2014-03-26 19:43:36.000000000 +0100
+@@ -5378,6 +5378,11 @@
+ expressions of the form "Symbol Op Symbol" */
+ BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM,
+
++/* This is a 32 bit reloc that stores the 32 bit pc relative
++value in two words (with an imm instruction). No relocation is
++done here - only used for relaxing */
++ BFD_RELOC_MICROBLAZE_32_NONE,
++
+ /* This is a 64 bit reloc that stores the 32 bit pc relative
+ value in two words (with an imm instruction). No relocation is
+ done here - only used for relaxing */
+diff -Nur gdb-7.7.orig/bfd/elf32-microblaze.c gdb-7.7/bfd/elf32-microblaze.c
+--- gdb-7.7.orig/bfd/elf32-microblaze.c 2013-12-08 05:55:47.000000000 +0100
++++ gdb-7.7/bfd/elf32-microblaze.c 2014-03-27 08:30:48.000000000 +0100
+@@ -177,6 +177,20 @@
+ FALSE), /* PC relative offset? */
+
+ /* This reloc does nothing. Used for relaxation. */
++ HOWTO (R_MICROBLAZE_32_NONE, /* Type. */
++ 0, /* Rightshift. */
++ 2, /* Size (0 = byte, 1 = short, 2 = long). */
++ 32, /* Bitsize. */
++ TRUE, /* PC_relative. */
++ 0, /* Bitpos. */
++ complain_overflow_bitfield, /* Complain on overflow. */
++ NULL, /* Special Function. */
++ "R_MICROBLAZE_32_NONE",/* Name. */
++ FALSE, /* Partial Inplace. */
++ 0, /* Source Mask. */
++ 0, /* Dest Mask. */
++ FALSE), /* PC relative offset? */
++
+ HOWTO (R_MICROBLAZE_64_NONE, /* Type. */
+ 0, /* Rightshift. */
+ 2, /* Size (0 = byte, 1 = short, 2 = long). */
+@@ -532,7 +546,10 @@
+ case BFD_RELOC_NONE:
+ microblaze_reloc = R_MICROBLAZE_NONE;
+ break;
+- case BFD_RELOC_MICROBLAZE_64_NONE:
++ case BFD_RELOC_MICROBLAZE_32_NONE:
++ microblaze_reloc = R_MICROBLAZE_32_NONE;
++ break;
++ case BFD_RELOC_MICROBLAZE_64_NONE:
+ microblaze_reloc = R_MICROBLAZE_64_NONE;
+ break;
+ case BFD_RELOC_32:
+@@ -668,6 +685,67 @@
+ return _bfd_elf_is_local_label_name (abfd, name);
+ }
+
++/* Support for core dump NOTE sections. */
++static bfd_boolean
++microblaze_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
++{
++ int offset;
++ unsigned int size;
++
++ switch (note->descsz)
++ {
++ default:
++ return FALSE;
++
++ case 228: /* Linux/MicroBlaze */
++ /* pr_cursig */
++ elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
++
++ /* pr_pid */
++ elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24);
++
++ /* pr_reg */
++ offset = 72;
++ size = 50 * 4;
++
++ break;
++ }
++
++ /* Make a ".reg/999" section. */
++ return _bfd_elfcore_make_pseudosection (abfd, ".reg",
++ size, note->descpos + offset);
++}
++
++static bfd_boolean
++microblaze_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
++{
++ switch (note->descsz)
++ {
++ default:
++ return FALSE;
++
++ case 128: /* Linux/MicroBlaze elf_prpsinfo */
++ elf_tdata (abfd)->core->program
++ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
++ elf_tdata (abfd)->core->command
++ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
++ }
++
++ /* Note that for some reason, a spurious space is tacked
++ onto the end of the args in some (at least one anyway)
++ implementations, so strip it off if it exists. */
++
++ {
++ char *command = elf_tdata (abfd)->core->command;
++ int n = strlen (command);
++
++ if (0 < n && command[n - 1] == ' ')
++ command[n - 1] = '\0';
++ }
++
++ return TRUE;
++}
++
+ /* The microblaze linker (like many others) needs to keep track of
+ the number of relocs that it decides to copy as dynamic relocs in
+ check_relocs for each symbol. This is so that it can later discard
+@@ -1023,7 +1101,7 @@
+ {
+ /* External symbol. */
+ bfd_boolean warned ATTRIBUTE_UNUSED;
+- bfd_boolean ignored ATTRIBUTE_UNUSED;
++ bfd_boolean ignored;
+
+ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+ r_symndx, symtab_hdr, sym_hashes,
+@@ -1852,14 +1930,22 @@
+ }
+ break;
+ case R_MICROBLAZE_NONE:
++ case R_MICROBLAZE_32_NONE:
+ {
+ /* This was a PC-relative instruction that was
+ completely resolved. */
+ int sfix, efix;
++ unsigned int val;
+ bfd_vma target_address;
+ target_address = irel->r_addend + irel->r_offset;
+ sfix = calc_fixup (irel->r_offset, 0, sec);
+ efix = calc_fixup (target_address, 0, sec);
++
++ /* Validate the in-band val. */
++ val = bfd_get_32 (abfd, contents + irel->r_offset);
++ if (val != irel->r_addend && ELF32_R_TYPE (irel->r_info) == R_MICROBLAZE_32_NONE) {
++ fprintf(stderr, "%d: CORRUPT relax reloc %x %lx\n", __LINE__, val, irel->r_addend);
++ }
+ irel->r_addend -= (efix - sfix);
+ /* Should use HOWTO. */
+ microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset,
+@@ -1907,6 +1993,49 @@
+ irelscanend = irelocs + o->reloc_count;
+ for (irelscan = irelocs; irelscan < irelscanend; irelscan++)
+ {
++ if (1 && ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_NONE)
++ {
++ unsigned int val;
++
++ isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
++
++ /* hax: We only do the following fixup for debug location lists. */
++ if (strcmp(".debug_loc", o->name))
++ continue;
++
++ /* This was a PC-relative instruction that was completely resolved. */
++ if (ocontents == NULL)
++ {
++ if (elf_section_data (o)->this_hdr.contents != NULL)
++ ocontents = elf_section_data (o)->this_hdr.contents;
++ else
++ {
++ /* We always cache the section contents.
++ Perhaps, if info->keep_memory is FALSE, we
++ should free them, if we are permitted to. */
++
++ if (o->rawsize == 0)
++ o->rawsize = o->size;
++ ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
++ if (ocontents == NULL)
++ goto error_return;
++ if (!bfd_get_section_contents (abfd, o, ocontents,
++ (file_ptr) 0,
++ o->rawsize))
++ goto error_return;
++ elf_section_data (o)->this_hdr.contents = ocontents;
++ }
++ }
++
++ val = bfd_get_32 (abfd, ocontents + irelscan->r_offset);
++ if (val != irelscan->r_addend) {
++ fprintf(stderr, "%d: CORRUPT relax reloc! %x %lx\n", __LINE__, val, irelscan->r_addend);
++ }
++
++ irelscan->r_addend -= calc_fixup (irelscan->r_addend, 0, sec);
++ microblaze_bfd_write_imm_value_32 (abfd, ocontents + irelscan->r_offset,
++ irelscan->r_addend);
++ }
+ if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32)
+ {
+ isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
+@@ -1966,7 +2095,7 @@
+ elf_section_data (o)->this_hdr.contents = ocontents;
+ }
+ }
+- irelscan->r_addend -= calc_fixup (irel->r_addend
++ irelscan->r_addend -= calc_fixup (irelscan->r_addend
+ + isym->st_value,
+ 0,
+ sec);
+@@ -3506,4 +3635,7 @@
+ #define elf_backend_size_dynamic_sections microblaze_elf_size_dynamic_sections
+ #define elf_backend_add_symbol_hook microblaze_elf_add_symbol_hook
+
++#define elf_backend_grok_prstatus microblaze_elf_grok_prstatus
++#define elf_backend_grok_psinfo microblaze_elf_grok_psinfo
++
+ #include "elf32-target.h"
+diff -Nur gdb-7.7.orig/bfd/libbfd.h gdb-7.7/bfd/libbfd.h
+--- gdb-7.7.orig/bfd/libbfd.h 2014-02-06 03:21:29.000000000 +0100
++++ gdb-7.7/bfd/libbfd.h 2014-03-26 20:02:00.000000000 +0100
+@@ -2615,6 +2615,7 @@
+ "BFD_RELOC_MICROBLAZE_32_ROSDA",
+ "BFD_RELOC_MICROBLAZE_32_RWSDA",
+ "BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM",
++ "BFD_RELOC_MICROBLAZE_32_NONE",
+ "BFD_RELOC_MICROBLAZE_64_NONE",
+ "BFD_RELOC_MICROBLAZE_64_GOTPC",
+ "BFD_RELOC_MICROBLAZE_64_GOT",
+diff -Nur gdb-7.7.orig/gdb/Makefile.in gdb-7.7/gdb/Makefile.in
+--- gdb-7.7.orig/gdb/Makefile.in 2014-02-06 03:21:29.000000000 +0100
++++ gdb-7.7/gdb/Makefile.in 2014-03-26 20:33:32.000000000 +0100
+@@ -849,7 +849,7 @@
+ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \
+ remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
+ sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
+-gdb_usleep.h jit.h xml-syscall.h microblaze-tdep.h \
++gdb_usleep.h jit.h xml-syscall.h microblaze-tdep.h microblaze-linux-tdep.h \
+ psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h \
+ amd64-darwin-tdep.h charset-list.h \
+ config/djgpp/langinfo.h config/djgpp/nl_types.h darwin-nat.h \
+@@ -1547,7 +1547,7 @@
+ m68kbsd-nat.c m68kbsd-tdep.c \
+ m68klinux-nat.c m68klinux-tdep.c \
+ m88k-tdep.c m88kbsd-nat.c \
+- microblaze-tdep.c microblaze-linux-tdep.c \
++ microblaze-tdep.c microblaze-linux-nat.c microblaze-linux-tdep.c \
+ mingw-hdep.c \
+ mips-linux-nat.c mips-linux-tdep.c \
+ mips-irix-tdep.c \
+diff -Nur gdb-7.7.orig/gdb/config/microblaze/linux.mh gdb-7.7/gdb/config/microblaze/linux.mh
+--- gdb-7.7.orig/gdb/config/microblaze/linux.mh 1970-01-01 01:00:00.000000000 +0100
++++ gdb-7.7/gdb/config/microblaze/linux.mh 2014-03-24 15:52:56.000000000 +0100
+@@ -0,0 +1,10 @@
++# Host: Microblaze, running Linux
++
++NAT_FILE= config/nm-linux.h
++NATDEPFILES= inf-ptrace.o fork-child.o \
++ microblaze-linux-nat.o proc-service.o linux-thread-db.o \
++ linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
++ linux-waitpid.o
++NAT_CDEPS = $(srcdir)/proc-service.list
++
++LOADLIBES = -ldl $(RDYNAMIC)
+diff -Nur gdb-7.7.orig/gdb/configure.host gdb-7.7/gdb/configure.host
+--- gdb-7.7.orig/gdb/configure.host 2013-12-08 05:55:47.000000000 +0100
++++ gdb-7.7/gdb/configure.host 2014-03-26 20:34:44.000000000 +0100
+@@ -59,6 +59,7 @@
+ 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 @@
+ 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 -Nur gdb-7.7.orig/gdb/configure.tgt gdb-7.7/gdb/configure.tgt
+--- gdb-7.7.orig/gdb/configure.tgt 2014-02-06 03:21:29.000000000 +0100
++++ gdb-7.7/gdb/configure.tgt 2014-03-26 20:36:23.000000000 +0100
+@@ -340,9 +340,10 @@
+
+ microblaze*-linux-*|microblaze*-*-linux*)
+ # Target: Xilinx MicroBlaze running Linux
+- gdb_target_obs="microblaze-tdep.o microblaze-linux-tdep.o microblaze-rom.o \
++ gdb_target_obs="microblaze-tdep.o microblaze-linux-tdep.o microblaze-rom.o glibc-tdep.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 -Nur gdb-7.7.orig/gdb/gdbserver/Makefile.in gdb-7.7/gdb/gdbserver/Makefile.in
+--- gdb-7.7.orig/gdb/gdbserver/Makefile.in 2014-02-06 03:21:29.000000000 +0100
++++ gdb-7.7/gdb/gdbserver/Makefile.in 2014-03-26 20:39:22.000000000 +0100
+@@ -148,6 +148,7 @@
+ $(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 \
+@@ -328,6 +329,7 @@
+ rm -f arm-with-iwmmxt.c
+ rm -f arm-with-vfpv2.c arm-with-vfpv3.c arm-with-neon.c
+ rm -f mips-linux.c mips64-linux.c
++ rm -f microblaze-linux.c
+ rm -f nios2-linux.c
+ rm -f powerpc-32.c powerpc-32l.c powerpc-64l.c powerpc-e500l.c
+ rm -f powerpc-altivec32l.c powerpc-cell32l.c powerpc-vsx32l.c
+@@ -600,6 +602,8 @@
+ $(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/reg-microblaze.dat $(regdat_sh)
++ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-microblaze.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 -Nur gdb-7.7.orig/gdb/gdbserver/configure.srv gdb-7.7/gdb/gdbserver/configure.srv
+--- gdb-7.7.orig/gdb/gdbserver/configure.srv 2014-01-08 10:23:36.000000000 +0100
++++ gdb-7.7/gdb/gdbserver/configure.srv 2014-03-26 20:40:44.000000000 +0100
+@@ -198,6 +198,13 @@
+ 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 -Nur gdb-7.7.orig/gdb/gdbserver/linux-microblaze-low.c gdb-7.7/gdb/gdbserver/linux-microblaze-low.c
+--- gdb-7.7.orig/gdb/gdbserver/linux-microblaze-low.c 1970-01-01 01:00:00.000000000 +0100
++++ gdb-7.7/gdb/gdbserver/linux-microblaze-low.c 2014-03-26 20:41:13.000000000 +0100
+@@ -0,0 +1,228 @@
++/* GNU/Linux/Microblaze specific low level interface, for the remote server for
++ GDB.
++ Copyright (C) 1995-2013 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 <sys/ptrace.h>
++
++#include "gdb_proc_service.h"
++
++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
++ };
++
++#define microblaze_num_regs (sizeof microblaze_regmap / sizeof microblaze_regmap[0])
++
++/* Defined in auto-generated file microblaze-linux.c. */
++void init_registers_microblaze (void);
++extern const struct target_desc *tdesc_microblaze;
++
++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 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 < 32; 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 < 32; 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, 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;
++}
++
++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,
++ microblaze_collect_ptrace_register,
++ microblaze_supply_ptrace_register,
++};
++
++void
++initialize_low_arch (void)
++{
++ init_registers_microblaze ();
++
++ initialize_regsets_info (&microblaze_regsets_info);
++}
+\ No newline at end of file
+diff -Nur gdb-7.7.orig/gdb/microblaze-linux-nat.c gdb-7.7/gdb/microblaze-linux-nat.c
+--- gdb-7.7.orig/gdb/microblaze-linux-nat.c 1970-01-01 01:00:00.000000000 +0100
++++ gdb-7.7/gdb/microblaze-linux-nat.c 2014-03-27 09:51:56.000000000 +0100
+@@ -0,0 +1,430 @@
++/* Microblaze GNU/Linux native support.
++
++ Copyright (C) 1988-1989, 1991-1992, 1994, 1996, 2000-2012 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 "defs.h"
++#include "arch-utils.h"
++#include "dis-asm.h"
++#include "frame.h"
++#include "trad-frame.h"
++#include "symtab.h"
++#include "value.h"
++#include "gdbcmd.h"
++#include "breakpoint.h"
++#include "inferior.h"
++#include "regcache.h"
++#include "target.h"
++#include "frame.h"
++#include "frame-base.h"
++#include "frame-unwind.h"
++#include "dwarf2-frame.h"
++#include "osabi.h"
++
++#include "gdb_assert.h"
++#include "target-descriptions.h"
++#include "opcodes/microblaze-opcm.h"
++#include "opcodes/microblaze-dis.h"
++
++#include "linux-nat.h"
++#include "target-descriptions.h"
++
++#include <sys/user.h>
++#include <sys/utsname.h>
++#include <sys/procfs.h>
++#include <sys/ptrace.h>
++
++/* Prototypes for supply_gregset etc. */
++#include "gregset.h"
++
++#include "microblaze-tdep.h"
++
++#include <elf/common.h>
++#include "auxv.h"
++
++/* Defines ps_err_e, struct ps_prochandle. */
++#include "gdb_proc_service.h"
++
++/* On GNU/Linux, threads are implemented as pseudo-processes, in which
++ case we may be tracing more than one process at a time. In that
++ case, inferior_ptid will contain the main process ID and the
++ individual thread (process) ID. get_thread_id () is used to get
++ the thread id if it's available, and the process id otherwise. */
++
++int
++get_thread_id (ptid_t ptid)
++{
++ int tid = ptid_get_lwp (ptid);
++ if (0 == tid)
++ tid = ptid_get_pid (ptid);
++ return tid;
++}
++
++#define GET_THREAD_ID(PTID) get_thread_id (PTID)
++
++/* Non-zero if our kernel may support the PTRACE_GETREGS and
++ PTRACE_SETREGS requests, for reading and writing the
++ general-purpose registers. Zero if we've tried one of
++ them and gotten an error. */
++int have_ptrace_getsetregs = 1;
++
++static int
++microblaze_register_u_addr (struct gdbarch *gdbarch, int regno)
++{
++ int u_addr = -1;
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace
++ interface, and not the wordsize of the program's ABI. */
++ int wordsize = sizeof (long);
++
++ /* General purpose registers occupy 1 slot each in the buffer. */
++ if (regno >= MICROBLAZE_R0_REGNUM
++ && regno <= MICROBLAZE_FSR_REGNUM)
++ u_addr = (regno * wordsize);
++
++ return u_addr;
++}
++
++
++static void
++fetch_register (struct regcache *regcache, int tid, int regno)
++{
++ struct gdbarch *gdbarch = get_regcache_arch (regcache);
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ /* This isn't really an address. But ptrace thinks of it as one. */
++ CORE_ADDR regaddr = microblaze_register_u_addr (gdbarch, regno);
++ int bytes_transferred;
++ unsigned int offset; /* Offset of registers within the u area. */
++ char buf[MAX_REGISTER_SIZE];
++
++ if (regaddr == -1)
++ {
++ memset (buf, '\0', register_size (gdbarch, regno)); /* Supply zeroes */
++ regcache_raw_supply (regcache, regno, buf);
++ return;
++ }
++
++ /* Read the raw register using sizeof(long) sized chunks. On a
++ 32-bit platform, 64-bit floating-point registers will require two
++ transfers. */
++ for (bytes_transferred = 0;
++ bytes_transferred < register_size (gdbarch, regno);
++ bytes_transferred += sizeof (long))
++ {
++ long l;
++
++ errno = 0;
++ l = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
++ regaddr += sizeof (long);
++ if (errno != 0)
++ {
++ char message[128];
++ sprintf (message, "reading register %s (#%d)",
++ gdbarch_register_name (gdbarch, regno), regno);
++ perror_with_name (message);
++ }
++ memcpy (&buf[bytes_transferred], &l, sizeof (l));
++ }
++
++ /* Now supply the register. Keep in mind that the regcache's idea
++ of the register's size may not be a multiple of sizeof
++ (long). */
++ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
++ {
++ /* Little-endian values are always found at the left end of the
++ bytes transferred. */
++ regcache_raw_supply (regcache, regno, buf);
++ }
++ else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
++ {
++ /* Big-endian values are found at the right end of the bytes
++ transferred. */
++ size_t padding = (bytes_transferred - register_size (gdbarch, regno));
++ regcache_raw_supply (regcache, regno, buf + padding);
++ }
++ else
++ internal_error (__FILE__, __LINE__,
++ _("fetch_register: unexpected byte order: %d"),
++ gdbarch_byte_order (gdbarch));
++}
++
++/* This function actually issues the request to ptrace, telling
++ it to get all general-purpose registers and put them into the
++ specified regset.
++
++ If the ptrace request does not exist, this function returns 0
++ and properly sets the have_ptrace_* flag. If the request fails,
++ this function calls perror_with_name. Otherwise, if the request
++ succeeds, then the regcache gets filled and 1 is returned. */
++static int
++fetch_all_gp_regs (struct regcache *regcache, int tid)
++{
++ struct gdbarch *gdbarch = get_regcache_arch (regcache);
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ gdb_gregset_t gregset;
++
++ if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
++ {
++ if (errno == EIO)
++ {
++ have_ptrace_getsetregs = 0;
++ return 0;
++ }
++ perror_with_name (_("Couldn't get general-purpose registers."));
++ }
++
++ supply_gregset (regcache, (const gdb_gregset_t *) &gregset);
++
++ return 1;
++}
++
++
++/* This is a wrapper for the fetch_all_gp_regs function. It is
++ responsible for verifying if this target has the ptrace request
++ that can be used to fetch all general-purpose registers at one
++ shot. If it doesn't, then we should fetch them using the
++ old-fashioned way, which is to iterate over the registers and
++ request them one by one. */
++static void
++fetch_gp_regs (struct regcache *regcache, int tid)
++{
++ struct gdbarch *gdbarch = get_regcache_arch (regcache);
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ int i;
++
++ if (have_ptrace_getsetregs)
++ if (fetch_all_gp_regs (regcache, tid))
++ return;
++
++ /* If we've hit this point, it doesn't really matter which
++ architecture we are using. We just need to read the
++ registers in the "old-fashioned way". */
++ for (i = MICROBLAZE_R0_REGNUM; i <= MICROBLAZE_FSR_REGNUM; i++)
++ fetch_register (regcache, tid, i);
++}
++
++
++static void
++store_register (const struct regcache *regcache, int tid, int regno)
++{
++ struct gdbarch *gdbarch = get_regcache_arch (regcache);
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ /* This isn't really an address. But ptrace thinks of it as one. */
++ CORE_ADDR regaddr = microblaze_register_u_addr (gdbarch, regno);
++ int i;
++ size_t bytes_to_transfer;
++ char buf[MAX_REGISTER_SIZE];
++
++ if (regaddr == -1)
++ return;
++
++ /* First collect the register. Keep in mind that the regcache's
++ idea of the register's size may not be a multiple of sizeof
++ (long). */
++ memset (buf, 0, sizeof buf);
++ bytes_to_transfer = align_up (register_size (gdbarch, regno), sizeof (long));
++ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
++ {
++ /* Little-endian values always sit at the left end of the buffer. */
++ regcache_raw_collect (regcache, regno, buf);
++ }
++ else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
++ {
++ /* Big-endian values sit at the right end of the buffer. */
++ size_t padding = (bytes_to_transfer - register_size (gdbarch, regno));
++ regcache_raw_collect (regcache, regno, buf + padding);
++ }
++
++ for (i = 0; i < bytes_to_transfer; i += sizeof (long))
++ {
++ long l;
++
++ memcpy (&l, &buf[i], sizeof (l));
++ errno = 0;
++ ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr, l);
++ regaddr += sizeof (long);
++
++ if (errno != 0)
++ {
++ char message[128];
++ sprintf (message, "writing register %s (#%d)",
++ gdbarch_register_name (gdbarch, regno), regno);
++ perror_with_name (message);
++ }
++ }
++}
++
++/* This function actually issues the request to ptrace, telling
++ it to store all general-purpose registers present in the specified
++ regset.
++
++ If the ptrace request does not exist, this function returns 0
++ and properly sets the have_ptrace_* flag. If the request fails,
++ this function calls perror_with_name. Otherwise, if the request
++ succeeds, then the regcache is stored and 1 is returned. */
++static int
++store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
++{
++ struct gdbarch *gdbarch = get_regcache_arch (regcache);
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ gdb_gregset_t gregset;
++
++ if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
++ {
++ if (errno == EIO)
++ {
++ have_ptrace_getsetregs = 0;
++ return 0;
++ }
++ perror_with_name (_("Couldn't get general-purpose registers."));
++ }
++
++ fill_gregset (regcache, &gregset, regno);
++
++ if (ptrace (PTRACE_SETREGS, tid, 0, (void *) &gregset) < 0)
++ {
++ if (errno == EIO)
++ {
++ have_ptrace_getsetregs = 0;
++ return 0;
++ }
++ perror_with_name (_("Couldn't set general-purpose registers."));
++ }
++
++ return 1;
++}
++
++/* This is a wrapper for the store_all_gp_regs function. It is
++ responsible for verifying if this target has the ptrace request
++ that can be used to store all general-purpose registers at one
++ shot. If it doesn't, then we should store them using the
++ old-fashioned way, which is to iterate over the registers and
++ store them one by one. */
++static void
++store_gp_regs (const struct regcache *regcache, int tid, int regno)
++{
++ struct gdbarch *gdbarch = get_regcache_arch (regcache);
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ int i;
++
++ if (have_ptrace_getsetregs)
++ if (store_all_gp_regs (regcache, tid, regno))
++ return;
++
++ /* If we hit this point, it doesn't really matter which
++ architecture we are using. We just need to store the
++ registers in the "old-fashioned way". */
++ for (i = MICROBLAZE_R0_REGNUM; i <= MICROBLAZE_FSR_REGNUM; i++)
++ store_register (regcache, tid, i);
++}
++
++
++/* Fetch registers from the child process. Fetch all registers if
++ regno == -1, otherwise fetch all general registers or all floating
++ point registers depending upon the value of regno. */
++
++static void
++microblaze_linux_fetch_inferior_registers (struct target_ops *ops,
++ struct regcache *regcache, int regno)
++{
++ /* Get the thread id for the ptrace call. */
++ int tid = GET_THREAD_ID (inferior_ptid);
++
++ if (regno == -1)
++ fetch_gp_regs (regcache, tid);
++ else
++ fetch_register (regcache, tid, regno);
++}
++
++/* Store registers back into the inferior. Store all registers if
++ regno == -1, otherwise store all general registers or all floating
++ point registers depending upon the value of regno. */
++
++static void
++microblaze_linux_store_inferior_registers (struct target_ops *ops,
++ struct regcache *regcache, int regno)
++{
++ /* Get the thread id for the ptrace call. */
++ int tid = GET_THREAD_ID (inferior_ptid);
++
++ if (regno >= 0)
++ store_register (regcache, tid, regno);
++ else
++ store_gp_regs (regcache, tid, -1);
++}
++
++/* Wrapper functions for the standard regset handling, used by
++ thread debugging. */
++
++void
++fill_gregset (const struct regcache *regcache,
++ gdb_gregset_t *gregsetp, int regno)
++{
++ microblaze_collect_gregset (NULL, regcache, regno, gregsetp);
++}
++
++void
++supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
++{
++ microblaze_supply_gregset (NULL, regcache, -1, gregsetp);
++}
++
++void
++fill_fpregset (const struct regcache *regcache,
++ gdb_fpregset_t *fpregsetp, int regno)
++{
++ /* FIXME. */
++}
++
++void
++supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
++{
++ /* FIXME. */
++}
++
++static const struct target_desc *
++microblaze_linux_read_description (struct target_ops *ops)
++{
++ CORE_ADDR microblaze_hwcap = 0;
++
++ if (target_auxv_search (ops, AT_HWCAP, &microblaze_hwcap) != 1)
++ return NULL;
++
++ return NULL;
++}
++
++
++void _initialize_microblaze_linux_nat (void);
++
++void
++_initialize_microblaze_linux_nat (void)
++{
++ struct target_ops *t;
++
++ /* Fill in the generic GNU/Linux methods. */
++ t = linux_target ();
++
++ /* Add our register access methods. */
++ t->to_fetch_registers = microblaze_linux_fetch_inferior_registers;
++ t->to_store_registers = microblaze_linux_store_inferior_registers;
++
++ t->to_read_description = microblaze_linux_read_description;
++
++ /* Register the target. */
++ linux_nat_add_target (t);
++}
+diff -Nur gdb-7.7.orig/gdb/microblaze-linux-tdep.c gdb-7.7/gdb/microblaze-linux-tdep.c
+--- gdb-7.7.orig/gdb/microblaze-linux-tdep.c 2014-01-08 10:23:36.000000000 +0100
++++ gdb-7.7/gdb/microblaze-linux-tdep.c 2014-03-26 10:11:41.000000000 +0100
+@@ -1,6 +1,6 @@
+ /* Target-dependent code for Xilinx MicroBlaze.
+
+- Copyright (C) 2009-2014 Free Software Foundation, Inc.
++ Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+@@ -32,11 +32,28 @@
+ #include "regset.h"
+ #include "solib-svr4.h"
+ #include "microblaze-tdep.h"
++#include "glibc-tdep.h"
+ #include "trad-frame.h"
+ #include "frame-unwind.h"
+ #include "tramp-frame.h"
+ #include "linux-tdep.h"
+
++static int microblaze_debug_flag = 0;
++
++static void
++microblaze_debug (const char *fmt, ...)
++{
++ if (microblaze_debug_flag)
++ {
++ va_list args;
++
++ va_start (args, fmt);
++ printf_unfiltered ("MICROBLAZE LINUX: ");
++ vprintf_unfiltered (fmt, args);
++ va_end (args);
++ }
++}
++
+ static int
+ microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
+@@ -46,20 +63,27 @@
+ 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
+ program modified the code on us, so it is wrong to put back the
+ old value. */
+ if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
+- val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
++ {
++ val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
++ microblaze_debug ("microblaze_linux_memory_remove_breakpoint writing back to memory at addr 0x%lx\n", addr);
++ }
+
++ do_cleanups (cleanup);
+ return val;
+ }
+
+@@ -116,6 +140,43 @@
+ microblaze_linux_sighandler_cache_init
+ };
+
++const struct microblaze_gregset microblaze_linux_core_gregset;
++
++static void
++microblaze_linux_supply_core_gregset (const struct regset *regset,
++ struct regcache *regcache,
++ int regnum, const void *gregs, size_t len)
++{
++ microblaze_supply_gregset (&microblaze_linux_core_gregset, regcache,
++ regnum, gregs);
++}
++
++static void
++microblaze_linux_collect_core_gregset (const struct regset *regset,
++ const struct regcache *regcache,
++ int regnum, void *gregs, size_t len)
++{
++ microblaze_collect_gregset (&microblaze_linux_core_gregset, regcache,
++ regnum, gregs);
++}
++
++static void
++microblaze_linux_supply_core_fpregset (const struct regset *regset,
++ struct regcache *regcache,
++ int regnum, const void *fpregs, size_t len)
++{
++ /* FIXME. */
++ microblaze_supply_fpregset (regcache, regnum, fpregs);
++}
++
++static void
++microblaze_linux_collect_core_fpregset (const struct regset *regset,
++ const struct regcache *regcache,
++ int regnum, void *fpregs, size_t len)
++{
++ /* FIXME. */
++ microblaze_collect_fpregset (regcache, regnum, fpregs);
++}
+
+ static void
+ microblaze_linux_init_abi (struct gdbarch_info info,
+@@ -123,6 +184,10 @@
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
++ tdep->gregset = regset_alloc (gdbarch, microblaze_linux_supply_core_gregset,
++ microblaze_linux_collect_core_gregset);
++ tdep->sizeof_gregset = 200;
++
+ linux_init_abi (info, gdbarch);
+
+ set_gdbarch_memory_remove_breakpoint (gdbarch,
+@@ -135,6 +200,25 @@
+ /* Trampolines. */
+ tramp_frame_prepend_unwinder (gdbarch,
+ &microblaze_linux_sighandler_tramp_frame);
++
++ /* BFD target for core files. */
++ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
++ set_gdbarch_gcore_bfd_target (gdbarch, "elf32-microblaze");
++ else
++ set_gdbarch_gcore_bfd_target (gdbarch, "elf32-microblazeel");
++
++
++ /* Shared library handling. */
++ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
++ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
++
++ set_gdbarch_regset_from_core_section (gdbarch,
++ microblaze_regset_from_core_section);
++
++ /* Enable TLS support. */
++ set_gdbarch_fetch_tls_load_module_address (gdbarch,
++ svr4_fetch_objfile_link_map);
++
+ }
+
+ /* -Wmissing-prototypes */
+diff -Nur gdb-7.7.orig/gdb/microblaze-rom.c gdb-7.7/gdb/microblaze-rom.c
+--- gdb-7.7.orig/gdb/microblaze-rom.c 2014-01-08 10:23:36.000000000 +0100
++++ gdb-7.7/gdb/microblaze-rom.c 2014-03-27 08:56:48.000000000 +0100
+@@ -1,6 +1,6 @@
+ /* Remote debugging interface to Xilinx MicroBlaze.
+
+- Copyright (C) 2009-2014 Free Software Foundation, Inc.
++ Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+@@ -21,7 +21,6 @@
+ #include "gdbcore.h"
+ #include "target.h"
+ #include "monitor.h"
+-#include <string.h>
+ #include "serial.h"
+ #include "regcache.h"
+
+diff -Nur gdb-7.7.orig/gdb/microblaze-tdep.c gdb-7.7/gdb/microblaze-tdep.c
+--- gdb-7.7.orig/gdb/microblaze-tdep.c 2014-02-06 03:21:29.000000000 +0100
++++ gdb-7.7/gdb/microblaze-tdep.c 2014-03-27 08:46:21.000000000 +0100
+@@ -1,6 +1,6 @@
+ /* Target-dependent code for Xilinx MicroBlaze.
+
+- Copyright (C) 2009-2014 Free Software Foundation, Inc.
++ Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+@@ -29,13 +29,13 @@
+ #include "inferior.h"
+ #include "regcache.h"
+ #include "target.h"
++#include "frame.h"
+ #include "frame-base.h"
+ #include "frame-unwind.h"
+ #include "dwarf2-frame.h"
+ #include "osabi.h"
+
+ #include "gdb_assert.h"
+-#include <string.h>
+ #include "target-descriptions.h"
+ #include "opcodes/microblaze-opcm.h"
+ #include "opcodes/microblaze-dis.h"
+@@ -73,7 +73,8 @@
+ "rpc", "rmsr", "rear", "resr", "rfsr", "rbtr",
+ "rpvr0", "rpvr1", "rpvr2", "rpvr3", "rpvr4", "rpvr5", "rpvr6",
+ "rpvr7", "rpvr8", "rpvr9", "rpvr10", "rpvr11",
+- "redr", "rpid", "rzpr", "rtlbx", "rtlbsx", "rtlblo", "rtlbhi"
++ "redr", "rpid", "rzpr", "rtlbx", "rtlbsx", "rtlblo", "rtlbhi",
++ "rslr", "rshr"
+ };
+
+ #define MICROBLAZE_NUM_REGS ARRAY_SIZE (microblaze_register_names)
+@@ -145,6 +146,14 @@
+ return sp;
+ }
+
++static CORE_ADDR
++microblaze_store_arguments (struct regcache *regcache, int nargs,
++ struct value **args, CORE_ADDR sp,
++ int struct_return, CORE_ADDR struct_addr)
++{
++ error (_("store_arguments not implemented"));
++ return sp;
++}
+
+ static CORE_ADDR
+ microblaze_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+@@ -156,14 +165,52 @@
+ return sp;
+ }
+
++static int
++microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
++ struct bp_target_info *bp_tgt)
++{
++ CORE_ADDR addr = bp_tgt->placed_address;
++ const unsigned char *bp;
++ 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
++ program modified the code on us, so it is wrong to put back the
++ old value. */
++ if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
++ {
++ val = target_write_raw_memory (addr, bp_tgt->shadow_contents, bplen);
++ microblaze_debug ("microblaze_linux_memory_remove_breakpoint writing back to memory at addr 0x%lx\n", addr);
++ }
++
++ do_cleanups (cleanup);
++ return val;
++}
++
+ static const gdb_byte *
+ microblaze_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc,
+ int *len)
+ {
++ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ static gdb_byte break_insn[] = MICROBLAZE_BREAKPOINT;
++ static gdb_byte break_insn_le[] = MICROBLAZE_BREAKPOINT_LE;
+
+ *len = sizeof (break_insn);
+- return break_insn;
++ if (byte_order == BFD_ENDIAN_BIG)
++ return break_insn;
++ else
++ return break_insn_le;
+ }
+
+ /* Allocate and initialize a frame cache. */
+@@ -178,6 +225,7 @@
+ /* Base address. */
+ cache->base = 0;
+ cache->pc = 0;
++ cache->saved_sp = 0;
+
+ /* Frameless until proven otherwise. */
+ cache->frameless_p = 1;
+@@ -234,6 +282,8 @@
+ int flags = 0;
+ int save_hidden_pointer_found = 0;
+ int non_stack_instruction_found = 0;
++ int n_insns;
++ unsigned int *insn_block;
+
+ /* Find the start of this function. */
+ find_pc_partial_function (pc, &name, &func_addr, &func_end);
+@@ -273,11 +323,18 @@
+ name, paddress (gdbarch, func_addr),
+ paddress (gdbarch, stop));
+
++/* Do a block read to minimize the transaction with the Debug Agent */
++ n_insns = (stop == func_addr) ? 1 : ((stop - func_addr) / INST_WORD_SIZE);
++ insn_block = calloc(n_insns, sizeof(unsigned long));
++
++ target_read_memory (func_addr, (void*) insn_block, n_insns * INST_WORD_SIZE );
++
+ for (addr = func_addr; addr < stop; addr += INST_WORD_SIZE)
+ {
+ insn = microblaze_fetch_instruction (addr);
++ //insn = insn_block[(addr - func_addr) / INST_WORD_SIZE];
+ op = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);
+- microblaze_debug ("%s %08lx\n", paddress (gdbarch, pc), insn);
++ microblaze_debug ("%s %08lx op=%x r%d r%d imm=%d\n", paddress (gdbarch, addr), insn, op, rd, ra, imm);
+
+ /* This code is very sensitive to what functions are present in the
+ prologue. It assumes that the (addi, addik, swi, sw) can be the
+@@ -291,6 +348,7 @@
+ cache->frameless_p = 0; /* Frame found. */
+ save_hidden_pointer_found = 0;
+ non_stack_instruction_found = 0;
++ cache->register_offsets[rd] = -imm;
+ continue;
+ }
+ else if (IS_SPILL_SP(op, rd, ra))
+@@ -401,8 +459,8 @@
+ part of the prologue. */
+ if (save_hidden_pointer_found)
+ prologue_end_addr -= INST_WORD_SIZE;
+-
+- return prologue_end_addr;
++ free(insn_block);
++ return prologue_end_addr;
+ }
+
+ static CORE_ADDR
+@@ -452,6 +510,7 @@
+ return start_pc;
+ }
+
++enum { REG_UNAVAIL = (CORE_ADDR) -1 };
+ /* Normal frames. */
+
+ static struct microblaze_frame_cache *
+@@ -459,7 +518,7 @@
+ {
+ struct microblaze_frame_cache *cache;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+- CORE_ADDR func;
++ CORE_ADDR current_pc;
+ int rn;
+
+ if (*this_cache)
+@@ -473,9 +532,18 @@
+ for (rn = 0; rn < gdbarch_num_regs (gdbarch); rn++)
+ cache->register_offsets[rn] = -1;
+
+- func = get_frame_func (next_frame);
++ cache->pc = get_frame_func (next_frame);
++ current_pc = get_frame_pc (next_frame);
++
++ if (cache->pc)
++ microblaze_analyze_prologue (gdbarch, cache->pc, current_pc,
++ cache);
+
+- cache->pc = get_frame_address_in_block (next_frame);
++ cache->base = get_frame_register_unsigned (next_frame, gdbarch_sp_regnum (gdbarch));
++ cache->saved_sp = cache->base + cache->framesize;
++
++ cache->register_offsets[MICROBLAZE_PREV_PC_REGNUM] = cache->base;
++ cache->register_offsets[MICROBLAZE_SP_REGNUM] = cache->saved_sp;
+
+ return cache;
+ }
+@@ -501,6 +569,14 @@
+ struct microblaze_frame_cache *cache =
+ microblaze_frame_cache (this_frame, this_cache);
+
++ if ((regnum == MICROBLAZE_SP_REGNUM &&
++ cache->register_offsets[MICROBLAZE_SP_REGNUM])
++ || (regnum == MICROBLAZE_FP_REGNUM &&
++ cache->register_offsets[MICROBLAZE_SP_REGNUM]))
++
++ return frame_unwind_got_constant (this_frame, regnum,
++ cache->register_offsets[MICROBLAZE_SP_REGNUM]);
++
+ if (cache->frameless_p)
+ {
+ if (regnum == MICROBLAZE_PC_REGNUM)
+@@ -508,11 +584,18 @@
+ if (regnum == MICROBLAZE_SP_REGNUM)
+ regnum = 1;
+ return trad_frame_get_prev_register (this_frame,
+- cache->saved_regs, regnum);
++ cache->saved_regs, regnum);
+ }
+- else
+- return trad_frame_get_prev_register (this_frame, cache->saved_regs,
+- regnum);
++
++ if (regnum == MICROBLAZE_PC_REGNUM)
++ {
++ regnum = 15;
++ return frame_unwind_got_memory (this_frame, regnum,
++ cache->register_offsets[MICROBLAZE_PREV_PC_REGNUM]);
++ }
++
++ return trad_frame_get_prev_register (this_frame, cache->saved_regs,
++ regnum);
+
+ }
+
+@@ -536,6 +619,12 @@
+ return cache->base;
+ }
+
++static const struct frame_unwind *
++microblaze_frame_sniffer (struct frame_info *next_frame)
++{
++ return &microblaze_frame_unwind;
++}
++
+ static const struct frame_base microblaze_frame_base =
+ {
+ &microblaze_frame_unwind,
+@@ -628,6 +717,109 @@
+ return (TYPE_LENGTH (type) == 16);
+ }
+
++int
++microblaze_software_single_step (struct frame_info *frame)
++{
++ struct gdbarch *arch = get_frame_arch (frame);
++ struct address_space *aspace = get_frame_address_space (frame);
++ struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
++ static char le_breakp[] = MICROBLAZE_BREAKPOINT_LE;
++ static char be_breakp[] = MICROBLAZE_BREAKPOINT;
++ enum bfd_endian byte_order = gdbarch_byte_order (arch);
++ char *breakp = byte_order == BFD_ENDIAN_BIG ? be_breakp : le_breakp;
++ int ret = 0;
++
++ /* Save the address and the values of the next_pc and the target */
++ static struct sstep_breaks
++ {
++ CORE_ADDR address;
++ bfd_boolean valid;
++ /* Shadow contents. */
++ char data[INST_WORD_SIZE];
++ } stepbreaks[2];
++ int ii;
++
++ if (1)
++ {
++ CORE_ADDR pc;
++ long insn;
++ enum microblaze_instr minstr;
++ bfd_boolean isunsignednum;
++ enum microblaze_instr_type insn_type;
++ short delay_slots;
++ int imm;
++ bfd_boolean immfound = FALSE;
++
++ /* Set a breakpoint at the next instruction */
++ /* If the current instruction is an imm, set it at the inst after */
++ /* If the instruction has a delay slot, skip the delay slot */
++ pc = get_frame_pc (frame);
++ insn = microblaze_fetch_instruction (pc);
++ minstr = get_insn_microblaze (insn, &isunsignednum, &insn_type, &delay_slots);
++ if (insn_type == immediate_inst)
++ {
++ int rd, ra, rb;
++ immfound = TRUE;
++ minstr = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);
++ pc = pc + INST_WORD_SIZE;
++ insn = microblaze_fetch_instruction (pc);
++ minstr = get_insn_microblaze (insn, &isunsignednum, &insn_type, &delay_slots);
++ }
++ stepbreaks[0].address = pc + (delay_slots * INST_WORD_SIZE) + INST_WORD_SIZE;
++ if (insn_type != return_inst) {
++ stepbreaks[0].valid = TRUE;
++ } else {
++ stepbreaks[0].valid = FALSE;
++ }
++
++ microblaze_debug ("single-step insn_type=%x insn=%x\n", insn_type, insn);
++ /* Now check for branch or return instructions */
++ if (insn_type == branch_inst || insn_type == return_inst) {
++ int limm;
++ int lrd, lra, lrb;
++ int ra, rb;
++ bfd_boolean targetvalid;
++ bfd_boolean unconditionalbranch;
++ microblaze_decode_insn(insn, &lrd, &lra, &lrb, &limm);
++ if (lra >= 0 && lra < MICROBLAZE_NUM_REGS)
++ ra = get_frame_register_unsigned (frame, lra);
++ else
++ ra = 0;
++ if (lrb >= 0 && lrb < MICROBLAZE_NUM_REGS)
++ rb = get_frame_register_unsigned (frame, lrb);
++ else
++ rb = 0;
++
++ stepbreaks[1].address = microblaze_get_target_address (insn, immfound, imm, pc, ra, rb, &targetvalid, &unconditionalbranch);
++ microblaze_debug ("single-step uncondbr=%d targetvalid=%d target=%x\n", unconditionalbranch, targetvalid, stepbreaks[1].address);
++
++ if (unconditionalbranch)
++ stepbreaks[0].valid = FALSE; /* This is a unconditional branch: will not come to the next address */
++ if (targetvalid && (stepbreaks[0].valid == FALSE ||
++ (stepbreaks[0].address != stepbreaks[1].address))
++ && (stepbreaks[1].address != pc)) {
++ stepbreaks[1].valid = TRUE;
++ } else {
++ stepbreaks[1].valid = FALSE;
++ }
++ } else {
++ stepbreaks[1].valid = FALSE;
++ }
++
++ /* Insert the breakpoints */
++ for (ii = 0; ii < 2; ++ii)
++ {
++
++ /* ignore invalid breakpoint. */
++ if (stepbreaks[ii].valid) {
++ insert_single_step_breakpoint (arch, aspace, stepbreaks[ii].address);
++ ret = 1;
++ }
++ }
++ }
++ return ret;
++}
++
+ static void
+ microblaze_write_pc (struct regcache *regcache, CORE_ADDR pc)
+ {
+@@ -664,6 +856,70 @@
+ return dwarf2_to_reg_map[reg];
+ }
+
++
++void
++microblaze_supply_gregset (const struct microblaze_gregset *gregset,
++ struct regcache *regcache,
++ int regnum, const void *gregs)
++{
++ unsigned int *regs = gregs;
++ if (regnum >= 0)
++ regcache_raw_supply (regcache, regnum, regs + regnum);
++
++ if (regnum == -1) {
++ int i;
++
++ for (i = 0; i < 50; i++) {
++ regcache_raw_supply (regcache, i, regs + i);
++ }
++ }
++}
++
++
++void
++microblaze_collect_gregset (const struct microblaze_gregset *gregset,
++ const struct regcache *regcache,
++ int regnum, void *gregs)
++{
++ /* FIXME. */
++}
++
++void
++microblaze_supply_fpregset (struct regcache *regcache,
++ int regnum, const void *fpregs)
++{
++ /* FIXME. */
++}
++
++void
++microblaze_collect_fpregset (const struct regcache *regcache,
++ int regnum, void *fpregs)
++{
++ /* FIXME. */
++}
++
++
++/* Return the appropriate register set for the core section identified
++ by SECT_NAME and SECT_SIZE. */
++
++const struct regset *
++microblaze_regset_from_core_section (struct gdbarch *gdbarch,
++ const char *sect_name, size_t sect_size)
++{
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++
++ microblaze_debug ("microblaze_regset_from_core_section, sect_name = %s\n", sect_name);
++
++ if (strcmp (sect_name, ".reg") == 0 && sect_size >= tdep->sizeof_gregset)
++ return tdep->gregset;
++
++ if (strcmp (sect_name, ".reg2") == 0 && sect_size >= tdep->sizeof_fpregset)
++ return tdep->fpregset;
++
++ microblaze_debug ("microblaze_regset_from_core_section returning null :-( \n");
++ return NULL;
++}
++
+ static struct gdbarch *
+ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+ {
+@@ -679,6 +935,11 @@
+ tdep = XMALLOC (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
++ tdep->gregset = NULL;
++ tdep->sizeof_gregset = 0;
++ tdep->fpregset = NULL;
++ tdep->sizeof_fpregset = 0;
++
+ set_gdbarch_long_double_bit (gdbarch, 128);
+
+ set_gdbarch_num_regs (gdbarch, MICROBLAZE_NUM_REGS);
+@@ -706,7 +967,10 @@
+ /* Stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
++ set_gdbarch_memory_remove_breakpoint (gdbarch, microblaze_linux_memory_remove_breakpoint);
++
+ set_gdbarch_breakpoint_from_pc (gdbarch, microblaze_breakpoint_from_pc);
++ set_gdbarch_software_single_step (gdbarch, microblaze_software_single_step);
+
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+
+@@ -725,6 +989,13 @@
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &microblaze_frame_unwind);
+ frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
++ //frame_base_append_sniffer (gdbarch, microblaze_frame_sniffer);
++
++ /* If we have register sets, enable the generic core file support. */
++ if (tdep->gregset) {
++ set_gdbarch_regset_from_core_section (gdbarch,
++ microblaze_regset_from_core_section);
++ }
+
+ return gdbarch;
+ }
+diff -Nur gdb-7.7.orig/gdb/microblaze-tdep.h gdb-7.7/gdb/microblaze-tdep.h
+--- gdb-7.7.orig/gdb/microblaze-tdep.h 2014-01-08 10:23:36.000000000 +0100
++++ gdb-7.7/gdb/microblaze-tdep.h 2014-03-26 10:11:41.000000000 +0100
+@@ -1,6 +1,6 @@
+ /* Target-dependent code for Xilinx MicroBlaze.
+
+- Copyright (C) 2009-2014 Free Software Foundation, Inc.
++ Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+@@ -22,8 +22,22 @@
+
+
+ /* Microblaze architecture-specific information. */
++struct microblaze_gregset
++{
++ unsigned int gregs[32];
++ unsigned int fpregs[32];
++ unsigned int pregs[16];
++};
++
+ struct gdbarch_tdep
+ {
++ int dummy; // declare something.
++
++ /* Register sets. */
++ struct regset *gregset;
++ size_t sizeof_gregset;
++ struct regset *fpregset;
++ size_t sizeof_fpregset;
+ };
+
+ struct microblaze_frame_cache
+@@ -42,7 +56,8 @@
+ int fp_regnum;
+
+ /* Offsets to saved registers. */
+- int register_offsets[57]; /* Must match MICROBLAZE_NUM_REGS. */
++ int register_offsets[59]; /* Must match MICROBLAZE_NUM_REGS. */
++ CORE_ADDR saved_sp;
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+@@ -66,11 +81,11 @@
+ MICROBLAZE_R12_REGNUM,
+ MICROBLAZE_R13_REGNUM,
+ MICROBLAZE_R14_REGNUM,
+- MICROBLAZE_R15_REGNUM,
++ MICROBLAZE_R15_REGNUM, MICROBLAZE_PREV_PC_REGNUM = MICROBLAZE_R15_REGNUM,
+ MICROBLAZE_R16_REGNUM,
+ MICROBLAZE_R17_REGNUM,
+ MICROBLAZE_R18_REGNUM,
+- MICROBLAZE_R19_REGNUM,
++ MICROBLAZE_R19_REGNUM, MICROBLAZE_FP_REGNUM = MICROBLAZE_R19_REGNUM,
+ MICROBLAZE_R20_REGNUM,
+ MICROBLAZE_R21_REGNUM,
+ MICROBLAZE_R22_REGNUM,
+@@ -107,7 +122,9 @@
+ MICROBLAZE_RTLBX_REGNUM,
+ MICROBLAZE_RTLBSX_REGNUM,
+ MICROBLAZE_RTLBLO_REGNUM,
+- MICROBLAZE_RTLBHI_REGNUM
++ MICROBLAZE_RTLBHI_REGNUM,
++ MICROBLAZE_SLR_REGNUM,
++ MICROBLAZE_SHR_REGNUM
+ };
+
+ /* All registers are 32 bits. */
+@@ -115,6 +132,21 @@
+
+ /* 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}
++
++extern void microblaze_supply_gregset (const struct microblaze_gregset *gregset,
++ struct regcache *regcache,
++ int regnum, const void *gregs);
++extern void microblaze_collect_gregset (const struct microblaze_gregset *gregset,
++ const struct regcache *regcache,
++ int regnum, void *gregs);
++extern void microblaze_supply_fpregset (struct regcache *regcache,
++ int regnum, const void *fpregs);
++extern void microblaze_collect_fpregset (const struct regcache *regcache,
++ int regnum, void *fpregs);
++
++extern const struct regset * microblaze_regset_from_core_section (struct gdbarch *gdbarch,
++ const char *sect_name, size_t sect_size);
+
+ #endif /* microblaze-tdep.h */
+diff -Nur gdb-7.7.orig/gdb/regformats/reg-microblaze.dat gdb-7.7/gdb/regformats/reg-microblaze.dat
+--- gdb-7.7.orig/gdb/regformats/reg-microblaze.dat 1970-01-01 01:00:00.000000000 +0100
++++ gdb-7.7/gdb/regformats/reg-microblaze.dat 2014-03-26 20:43:54.000000000 +0100
+@@ -0,0 +1,41 @@
++name:microblaze
++expedite:r1,pc
++32:r0
++32:r1
++32:r2
++32:r3
++32:r4
++32:r5
++32:r6
++32:r7
++32:r8
++32:r9
++32:r10
++32:r11
++32:r12
++32:r13
++32:r14
++32:r15
++32:r16
++32:r17
++32:r18
++32:r19
++32:r20
++32:r21
++32:r22
++32:r23
++32:r24
++32:r25
++32:r26
++32:r27
++32:r28
++32:r29
++32:r30
++32:r31
++32:pc
++32:msr
++32:ear
++32:esr
++32:fsr
++32:slr
++32:shr
+diff -Nur gdb-7.7.orig/include/elf/microblaze.h gdb-7.7/include/elf/microblaze.h
+--- gdb-7.7.orig/include/elf/microblaze.h 2013-12-08 05:11:51.000000000 +0100
++++ gdb-7.7/include/elf/microblaze.h 2014-03-26 20:44:34.000000000 +0100
+@@ -58,6 +58,7 @@
+ RELOC_NUMBER (R_MICROBLAZE_TLSDTPREL64, 27) /* TLS Offset Within TLS Block */
+ RELOC_NUMBER (R_MICROBLAZE_TLSGOTTPREL32, 28) /* TLS Offset From Thread Pointer */
+ RELOC_NUMBER (R_MICROBLAZE_TLSTPREL32, 29) /* TLS Offset From Thread Pointer */
++ RELOC_NUMBER (R_MICROBLAZE_32_NONE, 30)
+
+ END_RELOC_NUMBERS (R_MICROBLAZE_max)
+
+diff -Nur gdb-7.7.orig/opcodes/microblaze-opc.h gdb-7.7/opcodes/microblaze-opc.h
+--- gdb-7.7.orig/opcodes/microblaze-opc.h 2013-12-08 05:11:52.000000000 +0100
++++ gdb-7.7/opcodes/microblaze-opc.h 2014-03-26 20:45:46.000000000 +0100
+@@ -91,6 +91,7 @@
+ #define OPCODE_MASK_H3 0xFC000600 /* High 6 bits and bits 21, 22. */
+ #define OPCODE_MASK_H32 0xFC00FC00 /* High 6 bits and bit 16-21. */
+ #define OPCODE_MASK_H34B 0xFC0000FF /* High 6 bits and low 8 bits. */
++#define OPCODE_MASK_H35B 0xFC0004FF /* High 6 bits and low 9 bits. */
+ #define OPCODE_MASK_H34C 0xFC0007E0 /* High 6 bits and bits 21-26. */
+
+ /* New Mask for msrset, msrclr insns. */
+@@ -101,7 +102,7 @@
+ #define DELAY_SLOT 1
+ #define NO_DELAY_SLOT 0
+
+-#define MAX_OPCODES 289
++#define MAX_OPCODES 291
+
+ struct op_code_struct
+ {
+@@ -174,7 +175,9 @@
+ {"wic", INST_TYPE_R1_R2_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000068, OPCODE_MASK_H34B, wic, special_inst },
+ {"wdc", INST_TYPE_R1_R2_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000064, OPCODE_MASK_H34B, wdc, special_inst },
+ {"wdc.clear", INST_TYPE_R1_R2_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000066, OPCODE_MASK_H34B, wdcclear, special_inst },
++ {"wdc.ext.clear", INST_TYPE_R1_R2_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000466, OPCODE_MASK_H35B, wdcextclear, special_inst },
+ {"wdc.flush", INST_TYPE_R1_R2_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000074, OPCODE_MASK_H34B, wdcflush, special_inst },
++ {"wdc.ext.flush", INST_TYPE_R1_R2_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000476, OPCODE_MASK_H35B, wdcextflush, special_inst },
+ {"mts", INST_TYPE_SPECIAL_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MTS, 0x9400C000, OPCODE_MASK_H13S, mts, special_inst },
+ {"mfs", INST_TYPE_RD_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MFS, 0x94008000, OPCODE_MASK_H23S, mfs, special_inst },
+ {"br", INST_TYPE_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98000000, OPCODE_MASK_H124, br, branch_inst },
+diff -Nur gdb-7.7.orig/opcodes/microblaze-opcm.h gdb-7.7/opcodes/microblaze-opcm.h
+--- gdb-7.7.orig/opcodes/microblaze-opcm.h 2013-12-08 05:11:52.000000000 +0100
++++ gdb-7.7/opcodes/microblaze-opcm.h 2014-03-26 20:45:46.000000000 +0100
+@@ -31,9 +31,9 @@
+ idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput,
+ ncget, ncput, muli, bslli, bsrai, bsrli, mului, or, and, xor,
+ andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16,
+- wic, wdc, wdcclear, wdcflush, mts, mfs, mbar, br, brd,
+- brld, bra, brad, brald, microblaze_brk, beq, beqd, bne, bned, blt,
+- bltd, ble, bled, bgt, bgtd, bge, bged, ori, andi, xori, andni,
++ wic, wdc, wdcclear, wdcextclear, wdcflush, wdcextflush, mts, mfs, mbar,
++ br, brd, brld, bra, brad, brald, microblaze_brk, beq, beqd, bne, bned,
++ blt, bltd, ble, bled, bgt, bgtd, bge, bged, ori, andi, xori, andni,
+ imm, rtsd, rtid, rtbd, rted, bri, brid, brlid, brai, braid, bralid,
+ brki, beqi, beqid, bnei, bneid, blti, bltid, blei, bleid, bgti,
+ bgtid, bgei, bgeid, lbu, lbur, lhu, lhur, lw, lwr, lwx, sb, sbr, sh,