mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
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> Signed-off-by: Michael Eager <eager@eagercon.com>
246 lines
5.9 KiB
C++
246 lines
5.9 KiB
C++
/* GNU/Linux/Microblaze specific low level interface, for the remote server for
|
|
GDB.
|
|
Copyright (C) 1995-2025 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 "elf/common.h"
|
|
#include "nat/gdb_ptrace.h"
|
|
#include <endian.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
|
|
};
|
|
|
|
|
|
|
|
class microblaze_target : public linux_process_target
|
|
{
|
|
public:
|
|
|
|
const regs_info *get_regs_info () override;
|
|
|
|
const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
|
|
|
|
protected:
|
|
|
|
void low_arch_setup () override;
|
|
|
|
bool low_cannot_fetch_register (int regno) override;
|
|
|
|
bool low_cannot_store_register (int regno) override;
|
|
|
|
bool low_supports_breakpoints () override;
|
|
|
|
CORE_ADDR low_get_pc (regcache *regcache) override;
|
|
|
|
void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
|
|
|
|
bool low_breakpoint_at (CORE_ADDR pc) override;
|
|
};
|
|
|
|
/* The singleton target ops object. */
|
|
|
|
static microblaze_target the_microblaze_target;
|
|
|
|
constexpr auto microblaze_num_regs
|
|
= sizeof (microblaze_regmap) / sizeof (microblaze_regmap[0]);
|
|
|
|
/* Defined in auto-generated file microblaze-linux-generated.c. */
|
|
void init_registers_microblaze_linux ();
|
|
extern const target_desc *tdesc_microblaze_linux;
|
|
|
|
bool
|
|
microblaze_target::low_supports_breakpoints ()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
microblaze_target::low_cannot_store_register (int regno)
|
|
{
|
|
if (microblaze_regmap[regno] == -1 || regno == 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
microblaze_target::low_cannot_fetch_register (int regno)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
CORE_ADDR
|
|
microblaze_target::low_get_pc (regcache *regcache)
|
|
{
|
|
unsigned long pc;
|
|
|
|
collect_register_by_name (regcache, "rpc", &pc);
|
|
return pc;
|
|
}
|
|
|
|
void
|
|
microblaze_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
|
|
{
|
|
unsigned long newpc = pc;
|
|
|
|
supply_register_by_name (regcache, "rpc", &newpc);
|
|
}
|
|
|
|
/* dbtrap insn */
|
|
/* brki r16, 0x18; */
|
|
static const uint32_t microblaze_breakpoint = 0xba0c0018;
|
|
#define microblaze_breakpoint_len 4
|
|
|
|
const gdb_byte *
|
|
microblaze_target::sw_breakpoint_from_kind (int kind, int *size)
|
|
{
|
|
*size = microblaze_breakpoint_len;
|
|
return reinterpret_cast<const gdb_byte *> (µblaze_breakpoint);
|
|
}
|
|
|
|
bool
|
|
microblaze_target::low_breakpoint_at (CORE_ADDR where)
|
|
{
|
|
uint32_t insn;
|
|
|
|
read_memory (where, (unsigned char *) &insn, 4);
|
|
/* If necessary, recognize more trap instructions here. GDB only uses the
|
|
one. */
|
|
return insn == microblaze_breakpoint;
|
|
}
|
|
|
|
#ifdef HAVE_PTRACE_GETREGS
|
|
|
|
static void
|
|
microblaze_collect_ptrace_register (struct regcache *regcache, int regno,
|
|
char *buf)
|
|
{
|
|
memset (buf, 0, sizeof (long));
|
|
|
|
if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
|
{
|
|
collect_register (regcache, regno, buf);
|
|
}
|
|
else if (__BYTE_ORDER == __BIG_ENDIAN)
|
|
{
|
|
int size = register_size (regcache->tdesc, regno);
|
|
|
|
if (size < sizeof (long))
|
|
collect_register (regcache, regno, buf + sizeof (long) - size);
|
|
else
|
|
collect_register (regcache, regno, buf);
|
|
}
|
|
}
|
|
|
|
/* Collect GPRs from REGCACHE into BUF. */
|
|
|
|
static void microblaze_fill_gregset (struct regcache *regcache, void *buf)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < microblaze_num_regs; i++)
|
|
microblaze_collect_ptrace_register (regcache, i,
|
|
(char *) buf + microblaze_regmap[i]);
|
|
}
|
|
|
|
/* Supply GPRs from BUF into REGCACHE. */
|
|
|
|
static void
|
|
microblaze_store_gregset (struct regcache *regcache, const void *buf)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < microblaze_num_regs; i++)
|
|
supply_register (regcache, i, (char *) buf + microblaze_regmap[i]);
|
|
}
|
|
|
|
static struct regset_info microblaze_regsets[] = {
|
|
{ PTRACE_GETREGS, PTRACE_SETREGS, NT_PRSTATUS,
|
|
sizeof (elf_gregset_t), GENERAL_REGS,
|
|
microblaze_fill_gregset, microblaze_store_gregset
|
|
},
|
|
NULL_REGSET
|
|
};
|
|
#endif /* HAVE_PTRACE_GETREGS */
|
|
|
|
static struct usrregs_info microblaze_usrregs_info =
|
|
{
|
|
microblaze_num_regs,
|
|
microblaze_regmap,
|
|
};
|
|
|
|
#ifdef HAVE_PTRACE_GETREGS
|
|
static struct regsets_info microblaze_regsets_info =
|
|
{
|
|
microblaze_regsets, /* regsets */
|
|
0, /* num_regsets */
|
|
nullptr /* disabled_regsets */
|
|
};
|
|
#endif /* HAVE_PTRACE_GETREGS */
|
|
|
|
static struct regs_info microblaze_regs_info =
|
|
{
|
|
nullptr, /* regset_bitmap */
|
|
µblaze_usrregs_info,
|
|
#ifdef HAVE_PTRACE_GETREGS
|
|
µblaze_regsets_info
|
|
#endif /* HAVE_PTRACE_GETREGS */
|
|
};
|
|
|
|
const regs_info *
|
|
microblaze_target::get_regs_info ()
|
|
{
|
|
return µblaze_regs_info;
|
|
}
|
|
|
|
void
|
|
microblaze_target::low_arch_setup ()
|
|
{
|
|
current_process ()->tdesc = tdesc_microblaze_linux;
|
|
}
|
|
|
|
linux_process_target *the_linux_target = &the_microblaze_target;
|
|
|
|
void
|
|
initialize_low_arch ()
|
|
{
|
|
init_registers_microblaze_linux ();
|
|
#ifdef HAVE_PTRACE_GETREGS
|
|
initialize_regsets_info (µblaze_regsets_info);
|
|
#endif /* HAVE_PTRACE_GETREGS */
|
|
}
|