From a3328b4cdfc58783b5f290f22255b36e26a6fb14 Mon Sep 17 00:00:00 2001
From: Gopi Kumar Bulusu <gopi@sankhya.com>
Date: Thu, 7 May 2026 17:47:40 +0530
Subject: [PATCH] gdb/MicroBlaze: Add support for native linux gdb
This patch adds support for native microblazeel-linux-gdb including
support for debugging with core dump files. Code is based on Xilinx/AMD
git repository used for Yocto builds with changes for proper indentation
and removal of commented out code.
Testing with native gdb has been checked to be working. Can load and run
a program using commands like break, step and finish. When a core file is
specified to gdb; registers can be examined using info reg. Tested using
qemu-system-microblazeel from AMD/Xilinx Yocto 2025.2 release.
bfd/ChangeLog:
* elf32-microblaze.c (microblaze_elf_grok_prstatus): New function.
(microblaze_elf_grok_psinfo): Likewise.
gdb/ChangeLog:
* Makefile.in (HFILES_NO_SRCDIR): Add microblaze-linux-tdep.h
ALLDEPFILES: Add microblaze-linux-nat.c
* configure.host (gdb_host_cpu): set to microblaze,
(gdb_host): set to linux
* configure.nat (NAT_DEPFILES): Add microblaze-linux-nat.o
* configure.tgt (gdb_target_obs): Add glibc-tdep.o
* microblaze-linux-nat.c: New file
* microblaze-linux-tdep.c (struct microblaze_linux_gregset): Add,
(microblaze_linux_init_abi): core file support,
shared object file handling, (INIT_GDB_FILE):
Call initialize_tdesc_microblaze_linux
* microblaze-linux-tdep.h: New file
* microblaze-tdep.c (microblaze_analyze_prologue): Set
cache->register_offsets[rd] to -imm,
(microblaze_skip_prologue): Ignore sal when sal.line is zero,
(microblaze_frame_cache): Computed cache->saved_sp and set
cache->register_offsets[MICROBLAZE_PREV_PC_REGNUM] and likewise
for MICROBLAZE_SP_REGNUM, (microblaze_frame_prev_register): Add
special handling for MICROBLAZE_PC_REGNUM, MICROBLAZE_SP_REGNUM
and MICROBLAZE_FP_REGNUM,
(microblaze_supply_gregset): Add,
(microblaze_iterate_over_regset_sections): Add
(microblaze_gdbarch_init): Set default value for gregset,
sizeof_gregset, fpregset, sizeof_fpregset. When target has
register sets, enable generic core file support by calling
set_gdbarch_iterate_over_regset_sections
* microblaze-tdep.h (microblaze_gdbarch_tdep): Add gregset,
sizeof_gregset, fpregset, sizeof_fpregset,
(microblaze_regnum): Add MICROBLAZE_PREV_PC_REGNUM to r15,
MICROBLAZE_FP_REGNUM to r19,
(micrbolaze_frame_cache): Add saved_sp,
(microblaze_supply_gregset): Add
Signed-off-by: David Holsgrove <david.holsgrove@petalogix.com>
Signed-off-by: Nathan Rossi <nathan.rossi@petalogix.com>
Signed-off-by: Mahesh Bodapati <mbodapat@xilinx.com>
Signed-off-by: Gopi Kumar Bulusu <gopi@sankhya.com>
---
bfd/elf32-microblaze.c | 67 +++++++++++
gdb/Makefile.in | 2 +
gdb/configure.host | 3 +
gdb/configure.nat | 4 +
gdb/configure.tgt | 3 +-
gdb/microblaze-linux-nat.c | 223 ++++++++++++++++++++++++++++++++++++
gdb/microblaze-linux-tdep.c | 28 +++++
gdb/microblaze-linux-tdep.h | 24 ++++
gdb/microblaze-tdep.c | 97 +++++++++++++---
gdb/microblaze-tdep.h | 15 ++-
10 files changed, 449 insertions(+), 17 deletions(-)
create mode 100755 gdb/microblaze-linux-nat.c
create mode 100644 gdb/microblaze-linux-tdep.h
@@ -768,6 +768,70 @@ microblaze_elf_is_local_label_name (bfd *abfd, const char *name)
return _bfd_elf_is_local_label_name (abfd, name);
}
+/* Support for core dump NOTE sections. */
+
+static bool
+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);
+}
+
+/* Support for core dump psinfo. */
+
+static bool
+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;
+}
+
/* ELF linker hash entry. */
struct elf32_mb_link_hash_entry
@@ -3490,4 +3554,7 @@ microblaze_elf_add_symbol_hook (bfd *abfd,
#define elf_backend_late_size_sections microblaze_elf_late_size_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"
@@ -1523,6 +1523,7 @@ HFILES_NO_SRCDIR = \
memrange.h \
memtag.h \
microblaze-tdep.h \
+ microblaze-linux-tdep.h \
mi/mi-cmd-break.h \
mi/mi-cmds.h \
mi/mi-common.h \
@@ -1891,6 +1892,7 @@ ALLDEPFILES = \
m68k-linux-nat.c \
m68k-linux-tdep.c \
m68k-tdep.c \
+ microblaze-linux-nat.c \
microblaze-linux-tdep.c \
microblaze-tdep.c \
mingw-hdep.c \
@@ -60,6 +60,7 @@ hppa*) gdb_host_cpu=pa ;;
i[34567]86*) gdb_host_cpu=i386 ;;
loongarch*) gdb_host_cpu=loongarch ;;
m68*) gdb_host_cpu=m68k ;;
+microblaze*) gdb_host_cpu=microblaze ;;
mips*) gdb_host_cpu=mips ;;
powerpc* | rs6000) gdb_host_cpu=powerpc ;;
sparcv9 | sparc64) gdb_host_cpu=sparc ;;
@@ -129,6 +130,8 @@ m68*-*-openbsd*) gdb_host=obsd ;;
m88*-*-openbsd*) gdb_host=obsd ;;
+microblaze*-*-linux*) gdb_host=linux ;;
+
mips*-*-linux*) gdb_host=linux ;;
mips*-*-netbsdaout* | mips*-*-knetbsd*-gnu)
gdb_host=nbsd ;;
@@ -305,6 +305,10 @@ case ${gdb_host} in
# Host: Motorola m68k running GNU/Linux.
NATDEPFILES="${NATDEPFILES} m68k-linux-nat.o"
;;
+ microblaze)
+ # Host: Microblaze running GNU/Linux.
+ NATDEPFILES="${NATDEPFILES} microblaze-linux-nat.o"
+ ;;
mips)
# Host: Linux/MIPS
NATDEPFILES="${NATDEPFILES} linux-nat-trad.o \
@@ -427,7 +427,8 @@ mep-*-*)
microblaze*-linux-*|microblaze*-*-linux*)
# Target: Xilinx MicroBlaze running Linux
gdb_target_obs="microblaze-tdep.o microblaze-linux-tdep.o solib-svr4.o \
- solib-svr4-linux.o symfile-mem.o linux-tdep.o"
+ glibc-tdep.o solib-svr4-linux.o symfile-mem.o \
+ linux-tdep.o"
;;
microblaze*-*-*)
# Target: Xilinx MicroBlaze running standalone
new file mode 100755
@@ -0,0 +1,223 @@
+/* Native-dependent code for GNU/Linux MicroBlaze.
+ Copyright (C) 2021-2026 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 "regcache.h"
+#include "gregset.h"
+#include "linux-nat.h"
+#include "microblaze-tdep.h"
+#include "microblaze-linux-tdep.h"
+#include "nat/gdb_ptrace.h"
+
+#define MICROBLAZE_TARGET_HAS_GETREGS 0
+#define MICROBLAZE_TARGET_HAS_SETREGS 0
+
+/* ELF_NGREG from procfs.h (does not work) conflicts with asm/elf.h (works)
+ just use MICROBLAZE_FSR_REGNUM as NGREG. */
+
+static const int microblaze_greg_begin = MICROBLAZE_R1_REGNUM;
+static const int microblaze_greg_end = MICROBLAZE_FSR_REGNUM;
+
+/* MicroBlaze Linux native additions to the default linux support. */
+
+class microblaze_linux_nat_target final : public linux_nat_target
+{
+public:
+ /* Add our register access methods. */
+ void fetch_registers (struct regcache *regcache, int regnum) override;
+ void store_registers (struct regcache *regcache, int regnum) override;
+
+ /* Read suitable target description. */
+ const struct target_desc *read_description () override;
+};
+
+static microblaze_linux_nat_target the_microblaze_linux_nat_target;
+
+/* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
+ from regset GREGS into REGCACHE. */
+
+static void
+supply_gregset_regnum (struct regcache *regcache, const prgregset_t *gregs,
+ int regnum)
+{
+ const elf_greg_t *regp = *gregs;
+
+ /* Access all registers */
+ if (regnum == -1)
+ {
+ /* We fill the general purpose registers. */
+ for (int i = microblaze_greg_begin; i < microblaze_greg_end; i++)
+ regcache->raw_supply (i, regp + i);
+
+ /* Fill the inaccessible zero register with zero. */
+ regcache->raw_supply_zeroed (0);
+ }
+ else if (regnum == MICROBLAZE_R0_REGNUM)
+ regcache->raw_supply_zeroed (0);
+ else if (regnum >= microblaze_greg_begin && regnum < microblaze_greg_end)
+ regcache->raw_supply (regnum, regp + regnum);
+}
+
+/* Copy all general purpose registers from regset GREGS into REGCACHE. */
+
+void
+supply_gregset (struct regcache *regcache, const prgregset_t *gregs)
+{
+ supply_gregset_regnum (regcache, gregs, -1);
+}
+
+/* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
+ from REGCACHE into regset GREGS. */
+
+void
+fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum)
+{
+ elf_greg_t *regp = *gregs;
+ if (regnum == -1)
+ {
+ /* We fill the general purpose registers. */
+ for (int i = microblaze_greg_begin; i < microblaze_greg_end; i++)
+ regcache->raw_collect (i, regp + i);
+ }
+ else if (regnum >= microblaze_greg_begin && regnum < microblaze_greg_end)
+ regcache->raw_collect (regnum, regp + regnum);
+}
+
+/* Transfering floating-point registers between GDB, inferiors and cores.
+ Since MicroBlaze floating-point registers are the same as GPRs these do
+ nothing. */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs)
+{
+}
+
+void
+fill_fpregset (const struct regcache *regcache,
+ gdb_fpregset_t *fpregs, int regno)
+{
+}
+
+/* Wrapper function around ptrace. */
+
+static void
+fetch_target_gp_regs (int tid, elf_gregset_t *gregs)
+{
+ elf_greg_t *gregp = *gregs;
+
+#if MICROBLAZE_TARGET_HAS_GETREGS
+ if (ptrace (PTRACE_GETREGS, tid, 0, (long) gregp) < 0)
+ {
+ perror_with_name (_("Couldn't get registers"));
+ return;
+ }
+#error "this configuration did not work during testing"
+#else
+ for (int i = microblaze_greg_begin; i < microblaze_greg_end; i++)
+ {
+ errno = 0;
+ gregp[i] = ptrace (PTRACE_PEEKUSER, tid,
+ (PTRACE_TYPE_ARG3) (i * sizeof(elf_greg_t)), 0);
+ if (errno != 0)
+ {
+ perror_with_name (_("Couldn't get register"));
+ }
+ }
+#endif
+}
+
+
+/* Wrapper function around ptrace. */
+
+static void
+store_target_gp_regs ( int tid, elf_gregset_t *gregs)
+{
+ elf_greg_t *gregp = *gregs;
+
+#if MICROBLAZE_TARGET_HAS_SETREGS
+ if (ptrace (PTRACE_SETREGS, tid, 0, (long) gregp) < 0)
+ {
+ perror_with_name (_("Couldn't set registers"));
+ }
+#error "this configuration did not work during testing"
+#else
+ for (int i = microblaze_greg_begin; i < microblaze_greg_end; i++)
+ {
+ long l;
+ l = gregp[i];
+ errno = 0;
+ ptrace (PTRACE_POKEUSER, tid,
+ (PTRACE_TYPE_ARG3) (i * sizeof(elf_greg_t)), l);
+ if (errno != 0)
+ {
+ perror_with_name (_("Couldn't set register"));
+ }
+ }
+#endif
+}
+
+/* Return a target description for the current target. */
+
+const struct target_desc *
+microblaze_linux_nat_target::read_description ()
+{
+ return tdesc_microblaze_linux;
+}
+
+/* Fetch REGNUM (or all registers if REGNUM == -1) from the target
+ into REGCACHE using PTRACE_GETREGSET. */
+
+void
+microblaze_linux_nat_target::fetch_registers (struct regcache *regcache,
+ int regno)
+{
+ int tid;
+ elf_gregset_t gregs;
+
+ tid = get_ptrace_pid (regcache->ptid());
+
+ fetch_target_gp_regs (tid, &gregs);
+
+ supply_gregset_regnum (regcache, &gregs, regno);
+}
+
+
+/* Store REGNUM (or all registers if REGNUM == -1) to the target
+ from REGCACHE using PTRACE_SETREGSET. */
+
+void
+microblaze_linux_nat_target::store_registers (struct regcache *regcache,
+ int regno)
+{
+ int tid;
+ elf_gregset_t gregs;
+
+ tid = get_ptrace_pid (regcache->ptid());
+
+ fetch_target_gp_regs (tid, &gregs);
+ fill_gregset (regcache, &gregs, regno);
+ store_target_gp_regs (tid, &gregs);
+}
+
+/* Initialize MicroBlaze Linux native support. */
+
+INIT_GDB_FILE (microblaze_linux_nat)
+{
+ /* Register the target. */
+ linux_target = &the_microblaze_linux_nat_target;
+ add_inf_child_target (&the_microblaze_linux_nat_target);
+}
@@ -35,7 +35,9 @@
#include "frame-unwind.h"
#include "tramp-frame.h"
#include "linux-tdep.h"
+#include "glibc-tdep.h"
#include "solib-svr4-linux.h"
+#include "features/microblaze-linux.c"
static int
microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
@@ -115,11 +117,22 @@ static struct tramp_frame microblaze_linux_sighandler_tramp_frame =
microblaze_linux_sighandler_cache_init
};
+static struct regset microblaze_linux_gregset =
+ {
+ NULL,
+ microblaze_supply_gregset
+ };
static void
microblaze_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
{
+ struct microblaze_gdbarch_tdep *tdep =
+ gdbarch_tdep<microblaze_gdbarch_tdep> (gdbarch);
+
+ tdep->gregset = µblaze_linux_gregset;
+ tdep->sizeof_gregset = MICROBLAZE_REGISTER_SIZE * MICROBLAZE_REDR_REGNUM;
+
linux_init_abi (info, gdbarch, 0);
set_gdbarch_memory_remove_breakpoint (gdbarch,
@@ -131,10 +144,25 @@ microblaze_linux_init_abi (struct gdbarch_info info,
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch,
µblaze_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);
+
}
INIT_GDB_FILE (microblaze_linux_tdep)
{
gdbarch_register_osabi (bfd_arch_microblaze, 0, GDB_OSABI_LINUX,
microblaze_linux_init_abi);
+
+ /* Initialize linux target description. */
+ initialize_tdesc_microblaze_linux ();
}
new file mode 100644
@@ -0,0 +1,24 @@
+/* Target-dependent code for GNU/Linux on MicroBlaze.
+
+ Copyright (C) 2021-2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef MICROBLAZE_LINUX_TDEP_H
+#define MICROBLAZE_LINUX_TDEP_H
+ /* Target descriptions. */
+ extern struct target_desc *tdesc_microblaze_linux;
+
+#endif /* MICROBLAZE_LINUX_TDEP_H */
@@ -252,6 +252,7 @@ microblaze_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
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))
@@ -399,8 +400,7 @@ microblaze_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
{
sal = find_sal_for_pc (func_start, 0);
- if (sal.end < func_end
- && start_pc <= sal.end)
+ if (sal.line != 0 && sal.end <= func_end && start_pc <= sal.end)
start_pc = sal.end;
}
@@ -420,6 +420,7 @@ microblaze_frame_cache (const frame_info_ptr &next_frame, void **this_cache)
struct microblaze_frame_cache *cache;
struct gdbarch *gdbarch = get_frame_arch (next_frame);
int rn;
+ CORE_ADDR current_pc;
if (*this_cache)
return (struct microblaze_frame_cache *) *this_cache;
@@ -433,9 +434,15 @@ microblaze_frame_cache (const frame_info_ptr &next_frame, void **this_cache)
cache->register_offsets[rn] = -1;
/* Call for side effects. */
- get_frame_func (next_frame);
+ cache->pc = get_frame_func (next_frame);
- cache->pc = get_frame_address_in_block (next_frame);
+ current_pc = get_frame_pc (next_frame);
+ if (cache->pc)
+ microblaze_analyze_prologue (gdbarch, cache->pc, current_pc, cache);
+
+ 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;
}
@@ -461,19 +468,30 @@ microblaze_frame_prev_register (const frame_info_ptr &this_frame,
struct microblaze_frame_cache *cache =
microblaze_frame_cache (this_frame, this_cache);
- if (cache->frameless_p)
+ if ((regnum == MICROBLAZE_SP_REGNUM || regnum == MICROBLAZE_FP_REGNUM)
+ && cache->register_offsets[MICROBLAZE_SP_REGNUM])
{
- if (regnum == MICROBLAZE_PC_REGNUM)
- regnum = 15;
- if (regnum == MICROBLAZE_SP_REGNUM)
- regnum = 1;
- return trad_frame_get_prev_register (this_frame,
- cache->saved_regs, regnum);
+ return frame_unwind_got_constant
+ (this_frame, regnum,
+ cache->register_offsets[MICROBLAZE_SP_REGNUM]);
+ }
+
+ if (regnum == MICROBLAZE_PC_REGNUM)
+ {
+ regnum = MICROBLAZE_PREV_PC_REGNUM;
+
+ microblaze_debug ("prev pc is r15 @ frame offset 0x%x\n",
+ (int) cache->register_offsets[regnum] );
+
+ return frame_unwind_got_memory
+ (this_frame, regnum,
+ cache->register_offsets[MICROBLAZE_PREV_PC_REGNUM]);
}
- else
- return trad_frame_get_prev_register (this_frame, cache->saved_regs,
- regnum);
+ if (regnum == MICROBLAZE_SP_REGNUM)
+ regnum = 1;
+
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
}
static const struct frame_unwind_legacy microblaze_frame_unwind (
@@ -718,6 +736,42 @@ microblaze_register_g_packet_guesses (struct gdbarch *gdbarch)
tdesc_microblaze_with_stack_protect.get ());
}
+void
+microblaze_supply_gregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *gregs, size_t size)
+{
+ const gdb_byte *regs = (const gdb_byte *) gregs;
+
+ if (regnum >= 0)
+ regcache->raw_supply (regnum, regs + regnum * MICROBLAZE_REGISTER_SIZE);
+
+ if (regnum == -1) {
+ int i;
+
+ for (i = 0; i < MICROBLAZE_REDR_REGNUM; i++) {
+ regcache->raw_supply (i, regs + i * MICROBLAZE_REGISTER_SIZE);
+ }
+ }
+}
+
+
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
+
+static void
+microblaze_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
+{
+ microblaze_gdbarch_tdep *tdep
+ = gdbarch_tdep<microblaze_gdbarch_tdep> (gdbarch);
+
+ cb (".reg", tdep->sizeof_gregset, tdep->sizeof_gregset, tdep->gregset, NULL,
+ cb_data);
+}
+
static struct gdbarch *
microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
@@ -742,6 +796,7 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
"org.gnu.gdb.microblaze.core");
if (feature == NULL)
return NULL;
+
tdesc_data = tdesc_data_alloc ();
valid_p = 1;
@@ -769,6 +824,13 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
gdbarch *gdbarch
= gdbarch_alloc (&info, gdbarch_tdep_up (new microblaze_gdbarch_tdep));
+ microblaze_gdbarch_tdep *tdep
+ = gdbarch_tdep<microblaze_gdbarch_tdep> (gdbarch);
+
+ 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);
@@ -817,6 +879,13 @@ microblaze_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
if (tdesc_data != NULL)
tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
+ /* If we have register sets, enable the generic core file support. */
+ if (tdep->gregset)
+ {
+ set_gdbarch_iterate_over_regset_sections
+ (gdbarch, microblaze_iterate_over_regset_sections);
+ }
+
return gdbarch;
}
@@ -23,8 +23,14 @@
#include "gdbarch.h"
/* Microblaze architecture-specific information. */
+
struct microblaze_gdbarch_tdep : gdbarch_tdep_base
{
+ /* Register sets. */
+ struct regset *gregset;
+ size_t sizeof_gregset;
+ struct regset *fpregset;
+ size_t sizeof_fpregset;
};
/* Register numbers. */
@@ -45,11 +51,11 @@ enum microblaze_regnum
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,
@@ -98,6 +104,7 @@ struct microblaze_frame_cache
CORE_ADDR base;
CORE_ADDR pc;
+ CORE_ADDR saved_sp;
/* Do we have a frame? */
int frameless_p;
@@ -120,4 +127,8 @@ struct microblaze_frame_cache
Only used for native debugging. */
#define MICROBLAZE_BREAKPOINT {0xba, 0x0c, 0x00, 0x18}
+extern void microblaze_supply_gregset (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *gregs, size_t size);
+
#endif /* GDB_MICROBLAZE_TDEP_H */
--
2.47.3