diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2014-03-28 07:30:20 +0100 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2014-03-28 07:30:20 +0100 |
commit | 12c9d74bb923174117e28186e4a7698e623803a2 (patch) | |
tree | 5e65f724ddcf7a82b56f915cc4d09ba2b47a65b7 | |
parent | a47f1c5bff1fab6d622ac3d440f62cb4f6cdcc3a (diff) |
add support for microblaze native debugging from xilinx-gdb git repo
-rw-r--r-- | package/gdb/patches/microblaze.patch | 1842 |
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*)®buf_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 */ ++ µblaze_usrregs_info, ++ µblaze_regsets_info ++ }; ++ ++static const struct regs_info * ++microblaze_regs_info (void) ++{ ++ return ®s_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 *) µblaze_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 (µblaze_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, µblaze_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); ++ } ++} ++ + |