gdb10: Fixes for ARC

Here we add a couple of fixes and improvements for ARC processors.
All except 1 patch are already in the upstream "master" branch
and will be an essential part of GCC 11.x whenever it gets released.

The most important are first 4 patches (0005-0008) which introduce
support of full native GDB support in Linux on ARC.

And the rests are tiny, yet useful improvements.

Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
This commit is contained in:
Alexey Brodkin 2021-09-10 07:10:20 -07:00
parent d6eeff01a6
commit 8099a74750
13 changed files with 4966 additions and 0 deletions

View File

@ -0,0 +1,226 @@
From 977e6e7dc30737b2a8be382e604d2b998d446749 Mon Sep 17 00:00:00 2001
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
Date: Mon, 22 Aug 2016 19:39:46 +0300
Subject: [PATCH 06/20] arc: Add support for signal handlers
This patch adds the necessary infrastructure to handle signal frames for
ARC architecture. It is fairly similar to what any other architecture
would have. Linux specific parts will be in a separate patch.
v2 [1]:
- Make the logic of "arc_sigtramp_frame_sniffer ()" simpler.
[1] Tom's remark for the first version
https://sourceware.org/pipermail/gdb-patches/2020-November/173221.html
gdb/ChangeLog:
* arc-tdep.c (arc_make_sigtramp_frame_cache): New function.
(arc_sigtramp_frame_this_id): Likewise.
(arc_sigtramp_frame_prev_register): Likewise.
(arc_sigtramp_frame_sniffer): Likewise.
(arc_siftramp_frame_unwind): New global variable.
(arc_gdbarch_init): Use sigtramp capabilities.
(arc_dump_tdep): Print sigtramp fields.
* arc-tdep.h (gdbarch_tdep): Add sigtramp fields.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=b4e3cd0440109d0a5552d3313ccbd35c8103335b
---
gdb/ChangeLog | 11 +++++
gdb/arc-tdep.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/arc-tdep.h | 13 ++++++
3 files changed, 147 insertions(+)
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,14 @@
+2020-12-22 Anton Kolesov <anton.kolesov@synopsys.com>
+
+ * arc-tdep.c (arc_make_sigtramp_frame_cache): New function.
+ (arc_sigtramp_frame_this_id): Likewise.
+ (arc_sigtramp_frame_prev_register): Likewise.
+ (arc_sigtramp_frame_sniffer): Likewise.
+ (arc_siftramp_frame_unwind): New global variable.
+ (arc_gdbarch_init): Use sigtramp capabilities.
+ (arc_dump_tdep): Print sigtramp fields.
+ * arc-tdep.h (gdbarch_tdep): Add sigtramp fields.
+
2021-04-25 Joel Brobecker <brobecker@adacore.com>
* version.in: Set GDB version number to 10.2.
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1843,6 +1843,104 @@
reg->how = DWARF2_FRAME_REG_CFA;
}
+/* Signal trampoline frame unwinder. Allows frame unwinding to happen
+ from within signal handlers. */
+
+static struct arc_frame_cache *
+arc_make_sigtramp_frame_cache (struct frame_info *this_frame)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_cache\n");
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+ /* Allocate new frame cache instance and space for saved register info. */
+ struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ /* Get the stack pointer and use it as the frame base. */
+ cache->prev_sp = arc_frame_base_address (this_frame, NULL);
+
+ /* If the ARC-private target-dependent info doesn't have a table of
+ offsets of saved register contents within an OS signal context
+ structure, then there is nothing to analyze. */
+ if (tdep->sc_reg_offset == NULL)
+ return cache;
+
+ /* Find the address of the sigcontext structure. */
+ CORE_ADDR addr = tdep->sigcontext_addr (this_frame);
+
+ /* For each register, if its contents have been saved within the
+ sigcontext structure, determine the address of those contents. */
+ gdb_assert (tdep->sc_num_regs <= (ARC_LAST_REGNUM + 1));
+ for (int i = 0; i < tdep->sc_num_regs; i++)
+ {
+ if (tdep->sc_reg_offset[i] != ARC_OFFSET_NO_REGISTER)
+ cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i];
+ }
+
+ return cache;
+}
+
+/* Implement the "this_id" frame_unwind method for signal trampoline
+ frames. */
+
+static void
+arc_sigtramp_frame_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_this_id\n");
+
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ CORE_ADDR stack_addr = cache->prev_sp;
+ CORE_ADDR code_addr
+ = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
+ *this_id = frame_id_build (stack_addr, code_addr);
+}
+
+/* Get a register from a signal handler frame. */
+
+static struct value *
+arc_sigtramp_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_prev_register (regnum = %d)\n", regnum);
+
+ /* Make sure we've initialized the cache. */
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* Frame sniffer for signal handler frame. Only recognize a frame if we
+ have a sigcontext_addr handler in the target dependency. */
+
+static int
+arc_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct gdbarch_tdep *tdep;
+
+ if (arc_debug)
+ debug_printf ("arc: sigtramp_frame_sniffer\n");
+
+ tdep = gdbarch_tdep (get_frame_arch (this_frame));
+
+ /* If we have a sigcontext_addr handler, then just return 1 (same as the
+ "default_frame_sniffer ()"). */
+ return (tdep->sigcontext_addr != NULL && tdep->is_sigtramp != NULL
+ && tdep->is_sigtramp (this_frame));
+}
+
/* Structure defining the ARC ordinary frame unwind functions. Since we are
the fallback unwinder, we use the default frame sniffer, which always
accepts the frame. */
@@ -1858,6 +1956,21 @@
NULL
};
+/* Structure defining the ARC signal frame unwind functions. Custom
+ sniffer is used, because this frame must be accepted only in the right
+ context. */
+
+static const struct frame_unwind arc_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ arc_sigtramp_frame_this_id,
+ arc_sigtramp_frame_prev_register,
+ NULL,
+ arc_sigtramp_frame_sniffer,
+ NULL,
+ NULL
+};
+
static const struct frame_base arc_normal_base = {
&arc_frame_unwind,
@@ -2272,6 +2385,7 @@
/* Frame unwinders and sniffers. */
dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &arc_sigtramp_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &arc_frame_unwind);
frame_base_set_default (gdbarch, &arc_normal_base);
@@ -2350,6 +2464,15 @@
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
fprintf_unfiltered (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
+
+ fprintf_unfiltered (file, "arc_dump_tdep: is_sigtramp = <%s>\n",
+ host_address_to_string (tdep->is_sigtramp));
+ fprintf_unfiltered (file, "arc_dump_tdep: sigcontext_addr = <%s>\n",
+ host_address_to_string (tdep->sigcontext_addr));
+ fprintf_unfiltered (file, "arc_dump_tdep: sc_reg_offset = <%s>\n",
+ host_address_to_string (tdep->sc_reg_offset));
+ fprintf_unfiltered (file, "arc_dump_tdep: sc_num_regs = %d\n",
+ tdep->sc_num_regs);
}
/* This command accepts single argument - address of instruction to
--- a/gdb/arc-tdep.h
+++ b/gdb/arc-tdep.h
@@ -124,6 +124,19 @@
/* Whether target has hardware (aka zero-delay) loops. */
bool has_hw_loops;
+
+ /* Detect sigtramp. */
+ bool (*is_sigtramp) (struct frame_info *);
+
+ /* Get address of sigcontext for sigtramp. */
+ CORE_ADDR (*sigcontext_addr) (struct frame_info *);
+
+ /* Offset of registers in `struct sigcontext'. */
+ const int *sc_reg_offset;
+
+ /* Number of registers in sc_reg_offsets. Most likely a ARC_LAST_REGNUM,
+ but in theory it could be less, so it is kept separate. */
+ int sc_num_regs;
};
/* Utility functions used by other ARC-specific modules. */

View File

@ -0,0 +1,240 @@
From 27a456bbaa0c525e534195d17345c2e9268dd5d2 Mon Sep 17 00:00:00 2001
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
Date: Thu, 22 Dec 2016 21:52:16 +0300
Subject: [PATCH 07/20] arc: Add support for signal frames for Linux targets
Implement functions needed to unwind signal frames on ARC Linux targets.
gdb/ChangeLog
* arc-linux-tdep.c (arc_linux_sc_reg_offsets): New static variable.
(arc_linux_is_sigtramp): New function.
(arc_linux_sigcontext_addr): Likewise.
(arc_linux_init_osabi): Use them.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=d4af727286e3a9f177ba11677fbd3a012d36558a
---
gdb/ChangeLog | 7 +
gdb/arc-linux-tdep.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 188 insertions(+)
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,12 @@
2020-12-22 Anton Kolesov <anton.kolesov@synopsys.com>
+ * arc-linux-tdep.c (arc_linux_sc_reg_offsets): New static variable.
+ (arc_linux_is_sigtramp): New function.
+ (arc_linux_sigcontext_addr): Likewise.
+ (arc_linux_init_osabi): Use them.
+
+2020-12-22 Anton Kolesov <anton.kolesov@synopsys.com>
+
* arc-tdep.c (arc_make_sigtramp_frame_cache): New function.
(arc_sigtramp_frame_this_id): Likewise.
(arc_sigtramp_frame_prev_register): Likewise.
--- a/gdb/arc-linux-tdep.c
+++ b/gdb/arc-linux-tdep.c
@@ -33,6 +33,60 @@
#define REGOFF(offset) (offset * ARC_REGISTER_SIZE)
+/* arc_linux_sc_reg_offsets[i] is the offset of register i in the `struct
+ sigcontext'. Array index is an internal GDB register number, as defined in
+ arc-tdep.h:arc_regnum.
+
+ From <include/uapi/asm/sigcontext.h> and <include/uapi/asm/ptrace.h>.
+
+ The layout of this struct is tightly bound to "arc_regnum" enum
+ in arc-tdep.h. Any change of order in there, must be reflected
+ here as well. */
+static const int arc_linux_sc_reg_offsets[] = {
+ /* R0 - R12. */
+ REGOFF (22), REGOFF (21), REGOFF (20), REGOFF (19),
+ REGOFF (18), REGOFF (17), REGOFF (16), REGOFF (15),
+ REGOFF (14), REGOFF (13), REGOFF (12), REGOFF (11),
+ REGOFF (10),
+
+ /* R13 - R25. */
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER,
+
+ REGOFF (9), /* R26 (GP) */
+ REGOFF (8), /* FP */
+ REGOFF (23), /* SP */
+ ARC_OFFSET_NO_REGISTER, /* ILINK */
+ ARC_OFFSET_NO_REGISTER, /* R30 */
+ REGOFF (7), /* BLINK */
+
+ /* R32 - R59. */
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER, ARC_OFFSET_NO_REGISTER,
+ ARC_OFFSET_NO_REGISTER,
+
+ REGOFF (4), /* LP_COUNT */
+ ARC_OFFSET_NO_REGISTER, /* RESERVED */
+ ARC_OFFSET_NO_REGISTER, /* LIMM */
+ ARC_OFFSET_NO_REGISTER, /* PCL */
+
+ REGOFF (6), /* PC */
+ REGOFF (5), /* STATUS32 */
+ REGOFF (2), /* LP_START */
+ REGOFF (3), /* LP_END */
+ REGOFF (1), /* BTA */
+};
+
/* arc_linux_core_reg_offsets[i] is the offset in the .reg section of GDB
regnum i. Array index is an internal GDB register number, as defined in
arc-tdep.h:arc_regnum.
@@ -87,6 +141,127 @@
REGOFF (6) /* ERET */
};
+/* Is THIS_FRAME a sigtramp function - the function that returns from
+ signal handler into normal execution flow? This is the case if the PC is
+ either at the start of, or in the middle of the two instructions:
+
+ mov r8, __NR_rt_sigreturn ; __NR_rt_sigreturn == 139
+ trap_s 0 ; `swi' for ARC700
+
+ On ARC uClibc Linux this function is called __default_rt_sa_restorer.
+
+ Returns TRUE if this is a sigtramp frame. */
+
+static bool
+arc_linux_is_sigtramp (struct frame_info *this_frame)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ CORE_ADDR pc = get_frame_pc (this_frame);
+
+ if (arc_debug)
+ {
+ debug_printf ("arc-linux: arc_linux_is_sigtramp, pc=%s\n",
+ paddress(gdbarch, pc));
+ }
+
+ static const gdb_byte insns_be_hs[] = {
+ 0x20, 0x8a, 0x12, 0xc2, /* mov r8,nr_rt_sigreturn */
+ 0x78, 0x1e /* trap_s 0 */
+ };
+ static const gdb_byte insns_be_700[] = {
+ 0x20, 0x8a, 0x12, 0xc2, /* mov r8,nr_rt_sigreturn */
+ 0x22, 0x6f, 0x00, 0x3f /* swi */
+ };
+
+ gdb_byte arc_sigtramp_insns[sizeof (insns_be_700)];
+ size_t insns_sz;
+ if (arc_mach_is_arcv2 (gdbarch))
+ {
+ insns_sz = sizeof (insns_be_hs);
+ memcpy (arc_sigtramp_insns, insns_be_hs, insns_sz);
+ }
+ else
+ {
+ insns_sz = sizeof (insns_be_700);
+ memcpy (arc_sigtramp_insns, insns_be_700, insns_sz);
+ }
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
+ {
+ /* On little endian targets, ARC code section is in what is called
+ "middle endian", where half-words are in the big-endian order,
+ only bytes inside the halfwords are in the little endian order.
+ As a result it is very easy to convert big endian instruction to
+ little endian, since it is needed to swap bytes in the halfwords,
+ so there is no need to have information on whether that is a
+ 4-byte instruction or 2-byte. */
+ gdb_assert ((insns_sz % 2) == 0);
+ for (int i = 0; i < insns_sz; i += 2)
+ std::swap (arc_sigtramp_insns[i], arc_sigtramp_insns[i+1]);
+ }
+
+ gdb_byte buf[insns_sz];
+
+ /* Read the memory at the PC. Since we are stopped, any breakpoint must
+ have been removed. */
+ if (!safe_frame_unwind_memory (this_frame, pc, buf, insns_sz))
+ {
+ /* Failed to unwind frame. */
+ return FALSE;
+ }
+
+ /* Is that code the sigtramp instruction sequence? */
+ if (memcmp (buf, arc_sigtramp_insns, insns_sz) == 0)
+ return TRUE;
+
+ /* No - look one instruction earlier in the code... */
+ if (!safe_frame_unwind_memory (this_frame, pc - 4, buf, insns_sz))
+ {
+ /* Failed to unwind frame. */
+ return FALSE;
+ }
+
+ return (memcmp (buf, arc_sigtramp_insns, insns_sz) == 0);
+}
+
+/* Get sigcontext structure of sigtramp frame - it contains saved
+ registers of interrupted frame.
+
+ Stack pointer points to the rt_sigframe structure, and sigcontext can
+ be found as in:
+
+ struct rt_sigframe {
+ struct siginfo info;
+ struct ucontext uc;
+ ...
+ };
+
+ struct ucontext {
+ unsigned long uc_flags;
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ struct sigcontext uc_mcontext;
+ sigset_t uc_sigmask;
+ };
+
+ sizeof (struct siginfo) == 0x80
+ offsetof (struct ucontext, uc_mcontext) == 0x14
+
+ GDB cannot include linux headers and use offsetof () because those are
+ target headers and GDB might be built for a different run host. There
+ doesn't seem to be an established mechanism to figure out those offsets
+ via gdbserver, so the only way is to hardcode values in the GDB,
+ meaning that GDB will be broken if values will change. That seems to
+ be a very unlikely scenario and other arches (aarch64, alpha, amd64,
+ etc) in GDB hardcode values. */
+
+static CORE_ADDR
+arc_linux_sigcontext_addr (struct frame_info *this_frame)
+{
+ const int ucontext_offset = 0x80;
+ const int sigcontext_offset = 0x14;
+ return get_frame_sp (this_frame) + ucontext_offset + sigcontext_offset;
+}
+
/* Implement the "cannot_fetch_register" gdbarch method. */
static int
@@ -504,6 +679,12 @@
if (arc_debug)
debug_printf ("arc-linux: GNU/Linux OS/ABI initialization.\n");
+ /* Fill in target-dependent info in ARC-private structure. */
+ tdep->is_sigtramp = arc_linux_is_sigtramp;
+ tdep->sigcontext_addr = arc_linux_sigcontext_addr;
+ tdep->sc_reg_offset = arc_linux_sc_reg_offsets;
+ tdep->sc_num_regs = ARRAY_SIZE (arc_linux_sc_reg_offsets);
+
/* If we are using Linux, we have in uClibc
(libc/sysdeps/linux/arc/bits/setjmp.h):

View File

@ -0,0 +1,110 @@
From 7cf6f67aee277a37a7c648ca41a46a2c04aec2ed Mon Sep 17 00:00:00 2001
From: Shahab Vahedi <shahab@synopsys.com>
Date: Tue, 10 Nov 2020 19:34:57 +0100
Subject: [PATCH 08/20] arc: Take into account the REGNUM in supply/collect gdb
hooks
All the arc_linux_supply_*() target operations and the
arc_linux_collect_v2_regset() in arc-linux-tdep.c were
supplying/collecting all the registers in regcache as if the
REGNUM was set to -1.
The more efficient behavior is to examine the REGNUM and act
accordingly. That is what this patch does.
gdb/ChangeLog:
* arc-linux-tdep.c (supply_register): New.
(arc_linux_supply_gregset, arc_linux_supply_v2_regset,
arc_linux_collect_v2_regset): Consider REGNUM.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=46023bbe81355230b4e7b76d3084337823d02362
---
gdb/ChangeLog | 6 ++++++
gdb/arc-linux-tdep.c | 41 ++++++++++++++++++++++++++++++++---------
2 files changed, 38 insertions(+), 9 deletions(-)
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2020-12-22 Shahab Vahedi <shahab@synopsys.com>
+
+ * arc-linux-tdep.c (supply_register): New.
+ (arc_linux_supply_gregset, arc_linux_supply_v2_regset,
+ arc_linux_collect_v2_regset): Consider REGNUM.
+
2020-12-22 Anton Kolesov <anton.kolesov@synopsys.com>
* arc-linux-tdep.c (arc_linux_sc_reg_offsets): New static variable.
--- a/gdb/arc-linux-tdep.c
+++ b/gdb/arc-linux-tdep.c
@@ -535,6 +535,18 @@
}
}
+/* Populate REGCACHE with register REGNUM from BUF. */
+
+static void
+supply_register (struct regcache *regcache, int regnum, const gdb_byte *buf)
+{
+ /* Skip non-existing registers. */
+ if ((arc_linux_core_reg_offsets[regnum] == ARC_OFFSET_NO_REGISTER))
+ return;
+
+ regcache->raw_supply (regnum, buf + arc_linux_core_reg_offsets[regnum]);
+}
+
void
arc_linux_supply_gregset (const struct regset *regset,
struct regcache *regcache,
@@ -545,9 +557,14 @@
const bfd_byte *buf = (const bfd_byte *) gregs;
- for (int reg = 0; reg <= ARC_LAST_REGNUM; reg++)
- if (arc_linux_core_reg_offsets[reg] != ARC_OFFSET_NO_REGISTER)
- regcache->raw_supply (reg, buf + arc_linux_core_reg_offsets[reg]);
+ /* regnum == -1 means writing all the registers. */
+ if (regnum == -1)
+ for (int reg = 0; reg <= ARC_LAST_REGNUM; reg++)
+ supply_register (regcache, reg, buf);
+ else if (regnum <= ARC_LAST_REGNUM)
+ supply_register (regcache, regnum, buf);
+ else
+ gdb_assert_not_reached ("Invalid regnum in arc_linux_supply_gregset.");
}
void
@@ -558,9 +575,12 @@
const bfd_byte *buf = (const bfd_byte *) v2_regs;
/* user_regs_arcv2 is defined in linux arch/arc/include/uapi/asm/ptrace.h. */
- regcache->raw_supply (ARC_R30_REGNUM, buf);
- regcache->raw_supply (ARC_R58_REGNUM, buf + REGOFF (1));
- regcache->raw_supply (ARC_R59_REGNUM, buf + REGOFF (2));
+ if (regnum == -1 || regnum == ARC_R30_REGNUM)
+ regcache->raw_supply (ARC_R30_REGNUM, buf);
+ if (regnum == -1 || regnum == ARC_R58_REGNUM)
+ regcache->raw_supply (ARC_R58_REGNUM, buf + REGOFF (1));
+ if (regnum == -1 || regnum == ARC_R59_REGNUM)
+ regcache->raw_supply (ARC_R59_REGNUM, buf + REGOFF (2));
}
/* Populate BUF with register REGNUM from the REGCACHE. */
@@ -618,9 +638,12 @@
{
bfd_byte *buf = (bfd_byte *) v2_regs;
- regcache->raw_collect (ARC_R30_REGNUM, buf);
- regcache->raw_collect (ARC_R58_REGNUM, buf + REGOFF (1));
- regcache->raw_collect (ARC_R59_REGNUM, buf + REGOFF (2));
+ if (regnum == -1 || regnum == ARC_R30_REGNUM)
+ regcache->raw_collect (ARC_R30_REGNUM, buf);
+ if (regnum == -1 || regnum == ARC_R58_REGNUM)
+ regcache->raw_collect (ARC_R58_REGNUM, buf + REGOFF (1));
+ if (regnum == -1 || regnum == ARC_R59_REGNUM)
+ regcache->raw_collect (ARC_R59_REGNUM, buf + REGOFF (2));
}
/* Linux regset definitions. */

View File

@ -0,0 +1,413 @@
From 59a76f39ab17bf00545559c0c655ba89405d478d Mon Sep 17 00:00:00 2001
From: Anton Kolesov <anton.kolesov@synopsys.com>
Date: Fri, 14 Feb 2014 11:56:23 +0400
Subject: [PATCH 09/20] gdb: Add native support for ARC in GNU/Linux
With this patch in place it is possible to build a GDB that
can run on ARC (GNU/Linux) hosts for debugging ARC targets.
The "arc-linux-nat.c" is a rather small one that mostly deals
with registers and a few thread related hooks.
v2 [1]:
- Remove "void" from the input of "_initialize_arc_linux_nat ()"
[1] Tom's remark after the first patch
https://sourceware.org/pipermail/gdb-patches/2020-November/173223.html
gdb/ChangeLog:
* Makefile.in (ALLDEPFILES): Add arc-linux-nat.c.
* configure.host (host to gdb names): Add arc*-*-linux*.
* configure.nat (gdb_host_cpu): Add arc.
* arc-linux-nat.c: New.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=04c9f85efcd8df5fc482ce97c0104cc7dd5d19e6
---
gdb/ChangeLog | 7 +
gdb/Makefile.in | 1
gdb/arc-linux-nat.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/configure.host | 3
gdb/configure.nat | 4
5 files changed, 335 insertions(+)
create mode 100644 gdb/arc-linux-nat.c
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@
+2020-12-22 Anton Kolesov <anton.kolesov@synopsys.com>
+
+ * Makefile.in (ALLDEPFILES): Add arc-linux-nat.c.
+ * configure.host (host to gdb names): Add arc*-*-linux*.
+ * configure.nat (gdb_host_cpu): Add arc.
+ * arc-linux-nat.c: New.
+
2020-12-22 Shahab Vahedi <shahab@synopsys.com>
* arc-linux-tdep.c (supply_register): New.
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -2136,6 +2136,7 @@
amd64-obsd-tdep.c \
amd64-sol2-tdep.c \
amd64-tdep.c \
+ arc-linux-nat.c \
arc-tdep.c \
arm.c \
arm-bsd-tdep.c \
--- /dev/null
+++ b/gdb/arc-linux-nat.c
@@ -0,0 +1,320 @@
+/* Native-dependent code for GNU/Linux ARC.
+
+ Copyright 2020 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 "frame.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "gdbsupport/gdb_assert.h"
+#include "target.h"
+#include "linux-nat.h"
+#include "nat/gdb_ptrace.h"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#include "gdbsupport/gdb_wait.h"
+#include <fcntl.h>
+#include <sys/procfs.h>
+#include <linux/elf.h>
+
+#include "gregset.h"
+#include "arc-tdep.h"
+#include "arc-linux-tdep.h"
+#include "arch/arc.h"
+
+/* Defines ps_err_e, struct ps_prochandle. */
+#include "gdb_proc_service.h"
+
+/* Linux starting with 4.12 supports NT_ARC_V2 note type, which adds R30,
+ R58 and R59 registers, which are specific to ARC HS and aren't
+ available in ARC 700. */
+#if defined (NT_ARC_V2) && defined (__ARCHS__)
+#define ARC_HAS_V2_REGSET
+#endif
+
+class arc_linux_nat_target final : public linux_nat_target
+{
+public:
+ /* Add ARC register access methods. */
+ void fetch_registers (struct regcache *, int) override;
+ void store_registers (struct regcache *, int) override;
+
+ const struct target_desc *read_description () override;
+
+ /* Handle threads */
+ void low_prepare_to_resume (struct lwp_info *lp) override;
+};
+
+static arc_linux_nat_target the_arc_linux_nat_target;
+
+/* Read general registers from target process/thread (via ptrace)
+ into REGCACHE. */
+
+static void
+fetch_gregs (struct regcache *regcache, int regnum)
+{
+ const int tid = get_ptrace_pid (regcache->ptid ());
+ struct iovec iov;
+ gdb_gregset_t regs;
+
+ iov.iov_base = &regs;
+ iov.iov_len = sizeof (gdb_gregset_t);
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, (void *) &iov) < 0)
+ perror_with_name (_("Couldn't get general registers"));
+ else
+ arc_linux_supply_gregset (NULL, regcache, regnum, &regs, 0);
+}
+
+#ifdef ARC_HAS_V2_REGSET
+/* Read ARC v2 registers from target process/thread (via ptrace)
+ into REGCACHE. */
+
+static void
+fetch_v2_regs (struct regcache *regcache, int regnum)
+{
+ const int tid = get_ptrace_pid (regcache->ptid ());
+ struct iovec iov;
+ bfd_byte v2_buffer[ARC_LINUX_SIZEOF_V2_REGSET];
+
+ iov.iov_base = &v2_buffer;
+ iov.iov_len = ARC_LINUX_SIZEOF_V2_REGSET;
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_ARC_V2, (void *) &iov) < 0)
+ perror_with_name (_("Couldn't get ARC HS registers"));
+ else
+ arc_linux_supply_v2_regset (NULL, regcache, regnum, v2_buffer, 0);
+}
+#endif
+
+/* Store general registers from REGCACHE into the target process/thread. */
+
+static void
+store_gregs (const struct regcache *regcache, int regnum)
+{
+ const int tid = get_ptrace_pid (regcache->ptid ());
+ struct iovec iov;
+ gdb_gregset_t regs;
+
+ iov.iov_base = &regs;
+ iov.iov_len = sizeof (gdb_gregset_t);
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, (void *) &iov) < 0)
+ perror_with_name (_("Couldn't get general registers"));
+ else
+ {
+ arc_linux_collect_gregset (NULL, regcache, regnum, regs, 0);
+
+ if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, (void *) &iov) < 0)
+ perror_with_name (_("Couldn't write general registers"));
+ }
+}
+
+#ifdef ARC_HAS_V2_REGSET
+/* Store ARC v2 registers from REGCACHE into the target process/thread. */
+
+static void
+store_v2_regs (const struct regcache *regcache, int regnum)
+{
+ const int tid = get_ptrace_pid (regcache->ptid ());
+ struct iovec iov;
+ bfd_byte v2_buffer[ARC_LINUX_SIZEOF_V2_REGSET];
+
+ iov.iov_base = &v2_buffer;
+ iov.iov_len = ARC_LINUX_SIZEOF_V2_REGSET;
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_ARC_V2, (void *) &iov) < 0)
+ perror_with_name (_("Couldn't get ARC HS registers"));
+ else
+ {
+ arc_linux_collect_v2_regset (NULL, regcache, regnum, v2_buffer, 0);
+
+ if (ptrace (PTRACE_SETREGSET, tid, NT_ARC_V2, (void *) &iov) < 0)
+ perror_with_name (_("Couldn't write ARC HS registers"));
+ }
+}
+#endif
+
+/* Target operation: Read REGNUM register (all registers if REGNUM == -1)
+ from target process into REGCACHE. */
+
+void
+arc_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
+{
+
+ if (regnum == -1 || regnum <= ARC_LAST_REGNUM)
+ fetch_gregs (regcache, regnum);
+
+#ifdef ARC_HAS_V2_REGSET
+ if (regnum == -1
+ || regnum == ARC_R30_REGNUM
+ || regnum == ARC_R58_REGNUM
+ || regnum == ARC_R59_REGNUM)
+ fetch_v2_regs (regcache, regnum);
+#endif
+}
+
+/* Target operation: Store REGNUM register (all registers if REGNUM == -1)
+ to the target process from REGCACHE. */
+
+void
+arc_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
+{
+ if (regnum == -1 || regnum <= ARC_LAST_REGNUM)
+ store_gregs (regcache, regnum);
+
+#ifdef ARC_HAS_V2_REGSET
+ if (regnum == -1
+ || regnum == ARC_R30_REGNUM
+ || regnum == ARC_R58_REGNUM
+ || regnum == ARC_R59_REGNUM)
+ store_v2_regs (regcache, regnum);
+#endif
+}
+
+/* Copy general purpose register(s) from REGCACHE into regset GREGS.
+ This function is exported to proc-service.c */
+
+void
+fill_gregset (const struct regcache *regcache,
+ gdb_gregset_t *gregs, int regnum)
+{
+ arc_linux_collect_gregset (NULL, regcache, regnum, gregs, 0);
+}
+
+/* Copy all the general purpose registers from regset GREGS into REGCACHE.
+ This function is exported to proc-service.c. */
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregs)
+{
+ arc_linux_supply_gregset (NULL, regcache, -1, gregs, 0);
+}
+
+/* ARC doesn't have separate FP registers. This function is exported
+ to proc-service.c. */
+
+void
+fill_fpregset (const struct regcache *regcache,
+ gdb_fpregset_t *fpregsetp, int regnum)
+{
+ if (arc_debug)
+ debug_printf ("arc-linux-nat: fill_fpregset called.");
+ return;
+}
+
+/* ARC doesn't have separate FP registers. This function is exported
+ to proc-service.c. */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+ if (arc_debug)
+ debug_printf ("arc-linux-nat: supply_fpregset called.");
+ return;
+}
+
+/* Implement the "read_description" method of linux_nat_target. */
+
+const struct target_desc *
+arc_linux_nat_target::read_description ()
+{
+ /* This is a native target, hence description is hardcoded. */
+#ifdef __ARCHS__
+ arc_arch_features features (4, ARC_ISA_ARCV2);
+#else
+ arc_arch_features features (4, ARC_ISA_ARCV1);
+#endif
+ return arc_lookup_target_description (features);
+}
+
+/* As described in arc_linux_collect_gregset(), we need to write resume-PC
+ to ERET. However by default GDB for native targets doesn't write
+ registers if they haven't been changed. This is a callback called by
+ generic GDB, and in this callback we have to rewrite PC value so it
+ would force rewrite of register on target. It seems that the only
+ other arch that utilizes this hook is x86/x86-64 for HW breakpoint
+ support. But then, AFAIK no other arch has this stop_pc/eret
+ complexity.
+
+ No better way was found, other than this fake write of register value,
+ to force GDB into writing register to target. Is there any? */
+
+void
+arc_linux_nat_target::low_prepare_to_resume (struct lwp_info *lwp)
+{
+ /* When new processes and threads are created we do not have the address
+ space for them and calling get_thread_regcache will cause an internal
+ error in GDB. It looks like that checking for last_resume_kind is the
+ sensible way to determine processes for which we cannot get regcache.
+ Ultimately, a better way would be removing the need for
+ low_prepare_to_resume in the first place. */
+ if (lwp->last_resume_kind == resume_stop)
+ return;
+
+ struct regcache *regcache = get_thread_regcache (this, lwp->ptid);
+ struct gdbarch *gdbarch = regcache->arch ();
+
+ /* Read current PC value, then write it back. It is required to call
+ invalidate(), otherwise GDB will note that new value is equal to old
+ value and will skip write. */
+ ULONGEST new_pc;
+ regcache_cooked_read_unsigned (regcache, gdbarch_pc_regnum (gdbarch),
+ &new_pc);
+ regcache->invalidate (gdbarch_pc_regnum (gdbarch));
+ regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch),
+ new_pc);
+}
+
+/* Fetch the thread-local storage pointer for libthread_db. Note that
+ this function is not called from GDB, but is called from libthread_db.
+ This is required to debug multithreaded applications with NPTL. */
+
+ps_err_e
+ps_get_thread_area (struct ps_prochandle *ph, lwpid_t lwpid, int idx,
+ void **base)
+{
+ if (arc_debug >= 2)
+ debug_printf ("arc-linux-nat: ps_get_thread_area called");
+
+ if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
+ return PS_ERR;
+
+ /* IDX is the bias from the thread pointer to the beginning of the
+ thread descriptor. It has to be subtracted due to implementation
+ quirks in libthread_db. */
+ *base = (void *) ((char *) *base - idx);
+
+ return PS_OK;
+}
+
+/* Suppress warning from -Wmissing-prototypes. */
+void _initialize_arc_linux_nat ();
+void
+_initialize_arc_linux_nat ()
+{
+ /* Register the target. */
+ linux_target = &the_arc_linux_nat_target;
+ add_inf_child_target (&the_arc_linux_nat_target);
+}
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -60,6 +60,7 @@
aarch64*) gdb_host_cpu=aarch64 ;;
alpha*) gdb_host_cpu=alpha ;;
+arc*) gdb_host_cpu=arc ;;
arm*) gdb_host_cpu=arm ;;
hppa*) gdb_host_cpu=pa ;;
i[34567]86*) gdb_host_cpu=i386 ;;
@@ -91,6 +92,8 @@
gdb_host=nbsd ;;
alpha*-*-openbsd*) gdb_host=nbsd ;;
+arc*-*-linux*) gdb_host=linux ;;
+
arm*-*-freebsd*) gdb_host=fbsd ;;
arm*-*-linux*) gdb_host=linux ;;
arm*-*-netbsdelf* | arm*-*-knetbsd*-gnu)
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -238,6 +238,10 @@
nat/aarch64-linux.o \
nat/aarch64-sve-linux-ptrace.o"
;;
+ arc)
+ # Host: ARC based machine running GNU/Linux
+ NATDEPFILES="${NATDEPFILES} arc-linux-nat.o"
+ ;;
arm)
# Host: ARM based machine running GNU/Linux
NATDEPFILES="${NATDEPFILES} arm-linux-nat.o \

View File

@ -0,0 +1,49 @@
From f1369c8a098508296d4c28b97e1f196d94b7b506 Mon Sep 17 00:00:00 2001
From: Shahab Vahedi <shahab@synopsys.com>
Date: Tue, 22 Dec 2020 12:27:00 +0100
Subject: [PATCH 12/20] arc: Make variable name in comments uppercase
The word "regnum" in comments should be uppercase, because it
reflects a variable name in the code.
gdb/ChangeLog
* arc-linux-tdep.c: Replace "regnum" with "REGNUM" in comments.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=acf10cacc6bd596ef7327063038bb1ee020c07d0
---
gdb/ChangeLog | 4 ++++
gdb/arc-linux-tdep.c | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,7 @@
+2020-12-22 Shahab Vahedi <shahab@synopsys.com>
+
+ * arc-linux-tdep.c: Replace "regnum" with "REGNUM" in comments.
+
2020-12-22 Anton Kolesov <anton.kolesov@synopsys.com>
* Makefile.in (ALLDEPFILES): Add arc-linux-nat.c.
--- a/gdb/arc-linux-tdep.c
+++ b/gdb/arc-linux-tdep.c
@@ -557,7 +557,7 @@
const bfd_byte *buf = (const bfd_byte *) gregs;
- /* regnum == -1 means writing all the registers. */
+ /* REGNUM == -1 means writing all the registers. */
if (regnum == -1)
for (int reg = 0; reg <= ARC_LAST_REGNUM; reg++)
supply_register (regcache, reg, buf);
@@ -621,7 +621,7 @@
gdb_byte *buf = (gdb_byte *) gregs;
struct gdbarch *gdbarch = regcache->arch ();
- /* regnum == -1 means writing all the registers. */
+ /* REGNUM == -1 means writing all the registers. */
if (regnum == -1)
for (int reg = 0; reg <= ARC_LAST_REGNUM; reg++)
collect_register (regcache, gdbarch, reg, buf);

View File

@ -0,0 +1,28 @@
From 125e6622d74a7477943c88244c48a093537b3661 Mon Sep 17 00:00:00 2001
From: Anton Kolesov <Anton.Kolesov@synopsys.com>
Date: Wed, 28 Jun 2017 13:15:46 +0300
Subject: [PATCH 13/20] gdb: Log "pc" value in "arc_skip_prologue"
Log the "pc" address upon entering "arc_skip_prologue".
gdb/ChangeLog:
* arc-tdep.c (arc_skip_prologue): Log "pc" address.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=d56834cbfb7c14b2ad723c75cc56db2de3c0f0e7
---
gdb/arc-tdep.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1493,7 +1493,7 @@
arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
if (arc_debug)
- debug_printf ("arc: skip_prologue\n");
+ debug_printf ("arc: skip_prologue (pc=%s)\n", paddress (gdbarch, pc));
CORE_ADDR func_addr;
const char *func_name;

View File

@ -0,0 +1,32 @@
From cf33efc0d41a81c67511954fe75b7f63048d86a9 Mon Sep 17 00:00:00 2001
From: Shahab Vahedi <shahab@synopsys.com>
Date: Tue, 10 Dec 2019 16:25:08 +0100
Subject: [PATCH 14/20] gdb: Use correct feature in tdesc-regs for ARC
tdesc-regs.exp test fails for ARC because the test is not
using the correct XML files as target description. With
this change, the correct directory and files are used.
gdb/testsuite/ChangeLog:
2020-04-01 Shahab Vahedi <shahab@synopsys.com>
* gdb.xml/tdesc-regs.exp: Use correct core-regs for ARC.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=3eccb1c8bfd1f119bbc55bf2821d0e4d76116b67
---
gdb/testsuite/gdb.xml/tdesc-regs.exp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/gdb/testsuite/gdb.xml/tdesc-regs.exp
+++ b/gdb/testsuite/gdb.xml/tdesc-regs.exp
@@ -32,7 +32,8 @@
}
"arc*-*-*" {
set architecture "arc:ARCv2"
- set core-regs {arc-v2.xml}
+ set regdir "arc/"
+ set core-regs {core-v2.xml aux-v2.xml}
}
"arm*-*-*" {
set regdir "arm/"

View File

@ -0,0 +1,67 @@
From 4bbb306263d4258b279d64a6012f5817aff87e56 Mon Sep 17 00:00:00 2001
From: Shahab Vahedi <shahab@synopsys.com>
Date: Wed, 15 Jan 2020 00:14:24 +0100
Subject: [PATCH 15/20] gdb: Add default reggroups for ARC
There is no reggroups set in ARC. If a "maintenance print reggroups"
command is issued, the default register set is dumped (which is fine).
However, if a new group is added via an XML file, then that will
become the _only_ group. This behavior causes gdb.xml/tdesc-regs.exp
to fail.
Fixes gdb.xml/tdesc-regs.exp on ARC.
gdb/ChangeLog:
2020-01-15 Shahab Vahedi <shahab@synopsys.com>
* arc-tdep.c (arc_add_reggroups): New function.
(arc_gdbarch_init): Call arc_add_reggroups.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=d0cc52bdf2e6a586cac70000518c95619970619b
---
gdb/arc-tdep.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -27,6 +27,7 @@
#include "frame-base.h"
#include "frame-unwind.h"
#include "gdbcore.h"
+#include "reggroups.h"
#include "gdbcmd.h"
#include "objfiles.h"
#include "osabi.h"
@@ -1979,6 +1980,20 @@
arc_frame_base_address
};
+/* Add all the expected register sets into GDBARCH. */
+
+static void
+arc_add_reggroups (struct gdbarch *gdbarch)
+{
+ reggroup_add (gdbarch, general_reggroup);
+ reggroup_add (gdbarch, float_reggroup);
+ reggroup_add (gdbarch, system_reggroup);
+ reggroup_add (gdbarch, vector_reggroup);
+ reggroup_add (gdbarch, all_reggroup);
+ reggroup_add (gdbarch, save_reggroup);
+ reggroup_add (gdbarch, restore_reggroup);
+}
+
static enum arc_isa
mach_type_to_arc_isa (const unsigned long mach)
{
@@ -2382,6 +2397,9 @@
/* This doesn't include possible long-immediate value. */
set_gdbarch_max_insn_length (gdbarch, 4);
+ /* Add default register groups. */
+ arc_add_reggroups (gdbarch);
+
/* Frame unwinders and sniffers. */
dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
dwarf2_append_unwinders (gdbarch);

View File

@ -0,0 +1,288 @@
From 8b8464d228b46a2abd677a0a440e0d08da75df0b Mon Sep 17 00:00:00 2001
From: Shahab Vahedi <shahab@synopsys.com>
Date: Wed, 2 Jun 2021 15:30:16 +0300
Subject: [PATCH 16/20] arc: Construct disassembler options dynamically
The idea of this change is simple: Populate a data structure, namely
"disasm_option_and_arg_t" from "include/dis-asm.h", to encompass the
disassembly options and their possible arguments.
This will make it easier to manage or extend those options by adapting
entries in a data structure, "arc_options". There will be lesser need
to hard-code the options in the code itself. Moreover, ARC GDB will
use this population function, "disassembler_options_arc ()", to enable
the "set disassembler-option" for ARC targets. The gdb change will be
in a separate patch though.
The changes in this patch can be divided into:
1) Introduction of "disassembler_options_arc ()" that will return a
"disasm_option_and_arg_t" structure representing the disassembly
options and their likely arguments.
2) New data type "arc_options_arg_t" and new data "arc_options".
These are the internals for keeping track of options and arguments
entries that can easily be extended.
3) To print the options, the "print_arc_disassembler_options ()" has
been adjusted to use this dynamically built structure instead of having
them hard-coded inside.
To see this in effect, one can look into the output of:
$ ./binutils/objdump --help
...
The following ARC specific disassembler options are...
...
include/ChangeLog:
* dis-asm.h (disassembler_options_arc): New prototype.
opcodes/ChangeLog:
* arc-dis.c (arc_option_arg_t): New enumeration.
(arc_options): New variable.
(disassembler_options_arc): New function.
(print_arc_disassembler_options): Reimplement in terms of
"disassembler_options_arc".
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=8f467114435286e4f78b16fc1f5864acf6488fc0
---
include/ChangeLog | 4 +
include/dis-asm.h | 1
opcodes/ChangeLog | 8 ++
opcodes/arc-dis.c | 180 +++++++++++++++++++++++++++++++++++++++++++++---------
4 files changed, 166 insertions(+), 27 deletions(-)
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2021-06-02 Shahab Vahedi <shahab@synopsys.com>
+
+ * dis-asm.h (disassembler_options_arc): New prototype.
+
2020-09-12 H.J. Lu <hongjiu.lu@intel.com>
PR ld/26391
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -311,6 +311,7 @@
extern void disassemble_init_s390 (struct disassemble_info *);
extern void disassemble_init_wasm32 (struct disassemble_info *);
extern void disassemble_init_nds32 (struct disassemble_info *);
+extern const disasm_options_and_args_t *disassembler_options_arc (void);
extern const disasm_options_and_args_t *disassembler_options_arm (void);
extern const disasm_options_and_args_t *disassembler_options_mips (void);
extern const disasm_options_and_args_t *disassembler_options_powerpc (void);
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,11 @@
+2021-06-02 Shahab Vahedi <shahab@synopsys.com>
+
+ * arc-dis.c (arc_option_arg_t): New enumeration.
+ (arc_options): New variable.
+ (disassembler_options_arc): New function.
+ (print_arc_disassembler_options): Reimplement in terms of
+ "disassembler_options_arc".
+
2020-10-22 Andrew Burgess <andrew.burgess@embecosm.com>
* csky-dis.c (csky_get_disassembler): Don't return NULL when there
--- a/opcodes/arc-dis.c
+++ b/opcodes/arc-dis.c
@@ -1412,41 +1412,167 @@
return print_insn_arc;
}
+/* Indices into option argument vector for options that do require
+ an argument. Use ARC_OPTION_ARG_NONE for options that don't
+ expect an argument. */
+typedef enum
+{
+ ARC_OPTION_ARG_NONE = -1,
+ ARC_OPTION_ARG_ARCH,
+ ARC_OPTION_ARG_SIZE
+} arc_option_arg_t;
+
+/* Valid ARC disassembler options. */
+static struct
+{
+ const char *name;
+ const char *description;
+ arc_option_arg_t arg;
+} arc_options[] =
+{
+ { "cpu=", N_("Enforce the designated architecture while decoding."),
+ ARC_OPTION_ARG_ARCH },
+ { "dsp", N_("Recognize DSP instructions."),
+ ARC_OPTION_ARG_NONE },
+ { "spfp", N_("Recognize FPX SP instructions."),
+ ARC_OPTION_ARG_NONE },
+ { "dpfp", N_("Recognize FPX DP instructions."),
+ ARC_OPTION_ARG_NONE },
+ { "quarkse_em", N_("Recognize FPU QuarkSE-EM instructions."),
+ ARC_OPTION_ARG_NONE },
+ { "fpuda", N_("Recognize double assist FPU instructions."),
+ ARC_OPTION_ARG_NONE },
+ { "fpus", N_("Recognize single precision FPU instructions."),
+ ARC_OPTION_ARG_NONE },
+ { "fpud", N_("Recognize double precision FPU instructions."),
+ ARC_OPTION_ARG_NONE },
+ { "nps400", N_("Recognize NPS400 instructions."),
+ ARC_OPTION_ARG_NONE },
+ { "hex", N_("Use only hexadecimal number to print immediates."),
+ ARC_OPTION_ARG_NONE }
+};
+
+/* Populate the structure for representing ARC's disassembly options.
+ Such a dynamic initialization is desired, because it makes the maintenance
+ easier and also gdb uses this to enable the "disassembler-option". */
+
+const disasm_options_and_args_t *
+disassembler_options_arc (void)
+{
+ static disasm_options_and_args_t *opts_and_args;
+
+ if (opts_and_args == NULL)
+ {
+ disasm_option_arg_t *args;
+ disasm_options_t *opts;
+ size_t i;
+ const size_t nr_of_options = ARRAY_SIZE (arc_options);
+ /* There is a null element at the end of CPU_TYPES, therefore
+ NR_OF_CPUS is actually 1 more and that is desired here too. */
+ const size_t nr_of_cpus = ARRAY_SIZE (cpu_types);
+
+ opts_and_args = XNEW (disasm_options_and_args_t);
+ opts_and_args->args
+ = XNEWVEC (disasm_option_arg_t, ARC_OPTION_ARG_SIZE + 1);
+ opts_and_args->options.name
+ = XNEWVEC (const char *, nr_of_options + 1);
+ opts_and_args->options.description
+ = XNEWVEC (const char *, nr_of_options + 1);
+ opts_and_args->options.arg
+ = XNEWVEC (const disasm_option_arg_t *, nr_of_options + 1);
+
+ /* Populate the arguments for "cpu=" option. */
+ args = opts_and_args->args;
+ args[ARC_OPTION_ARG_ARCH].name = "ARCH";
+ args[ARC_OPTION_ARG_ARCH].values = XNEWVEC (const char *, nr_of_cpus);
+ for (i = 0; i < nr_of_cpus; ++i)
+ args[ARC_OPTION_ARG_ARCH].values[i] = cpu_types[i].name;
+ args[ARC_OPTION_ARG_SIZE].name = NULL;
+ args[ARC_OPTION_ARG_SIZE].values = NULL;
+
+ /* Populate the options. */
+ opts = &opts_and_args->options;
+ for (i = 0; i < nr_of_options; ++i)
+ {
+ opts->name[i] = arc_options[i].name;
+ opts->description[i] = arc_options[i].description;
+ if (arc_options[i].arg != ARC_OPTION_ARG_NONE)
+ opts->arg[i] = &args[arc_options[i].arg];
+ else
+ opts->arg[i] = NULL;
+ }
+ opts->name[nr_of_options] = NULL;
+ opts->description[nr_of_options] = NULL;
+ opts->arg[nr_of_options] = NULL;
+ }
+
+ return opts_and_args;
+}
+
+
void
print_arc_disassembler_options (FILE *stream)
{
- int i;
+ const disasm_options_and_args_t *opts_and_args;
+ const disasm_option_arg_t *args;
+ const disasm_options_t *opts;
+ size_t i, j;
+ size_t max_len = 0;
+
+ opts_and_args = disassembler_options_arc ();
+ opts = &opts_and_args->options;
+ args = opts_and_args->args;
- fprintf (stream, _("\n\
-The following ARC specific disassembler options are supported for use \n\
-with -M switch (multiple options should be separated by commas):\n"));
+ fprintf (stream, _("\nThe following ARC specific disassembler options are"
+ " supported for use \nwith the -M switch (multiple"
+ " options should be separated by commas):\n"));
+
+ /* Find the maximum length for printing options (and their arg name). */
+ for (i = 0; opts->name[i] != NULL; ++i)
+ {
+ size_t len = strlen (opts->name[i]);
+ len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0;
+ max_len = (len > max_len) ? len : max_len;
+ }
+
+ /* Print the options, their arg and description, if any. */
+ for (i = 0, ++max_len; opts->name[i] != NULL; ++i)
+ {
+ fprintf (stream, " %s", opts->name[i]);
+ if (opts->arg[i] != NULL)
+ fprintf (stream, "%s", opts->arg[i]->name);
+ if (opts->description[i] != NULL)
+ {
+ size_t len = strlen (opts->name[i]);
+ len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0;
+ fprintf (stream,
+ "%*c %s", (int) (max_len - len), ' ', opts->description[i]);
+ }
+ fprintf (stream, _("\n"));
+ }
- /* cpu=... options. */
- for (i = 0; cpu_types[i].name; ++i)
+ /* Print the possible values of an argument. */
+ for (i = 0; args[i].name != NULL; ++i)
{
- /* As of now all value CPU values are less than 16 characters. */
- fprintf (stream, " cpu=%-16s\tEnforce %s ISA.\n",
- cpu_types[i].name, cpu_types[i].isa);
+ size_t len = 3;
+ fprintf (stream, _("\n\
+ For the options above, the following values are supported for \"%s\":\n "),
+ args[i].name);
+ for (j = 0; args[i].values[j] != NULL; ++j)
+ {
+ fprintf (stream, " %s", args[i].values[j]);
+ len += strlen (args[i].values[j]) + 1;
+ /* reset line if printed too long. */
+ if (len >= 78)
+ {
+ fprintf (stream, _("\n "));
+ len = 3;
+ }
+ }
+ fprintf (stream, _("\n"));
}
- fprintf (stream, _("\
- dsp Recognize DSP instructions.\n"));
- fprintf (stream, _("\
- spfp Recognize FPX SP instructions.\n"));
- fprintf (stream, _("\
- dpfp Recognize FPX DP instructions.\n"));
- fprintf (stream, _("\
- quarkse_em Recognize FPU QuarkSE-EM instructions.\n"));
- fprintf (stream, _("\
- fpuda Recognize double assist FPU instructions.\n"));
- fprintf (stream, _("\
- fpus Recognize single precision FPU instructions.\n"));
- fprintf (stream, _("\
- fpud Recognize double precision FPU instructions.\n"));
- fprintf (stream, _("\
- nps400 Recognize NPS400 instructions.\n"));
- fprintf (stream, _("\
- hex Use only hexadecimal number to print immediates.\n"));
+ fprintf (stream, _("\n"));
}
void arc_insn_decode (bfd_vma addr,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,101 @@
From b99b999fc7a0d0888b62e3bdedd0b4855bdf955c Mon Sep 17 00:00:00 2001
From: Shahab Vahedi <shahab@synopsys.com>
Date: Fri, 16 Jul 2021 16:49:15 +0200
Subject: [PATCH 18/20] gdb: Fix numerical field extraction for target
description "flags"
The "val_print_type_code_flags ()" function is responsible for
extraction of fields for "flags" data type. These data types are
used when describing a custom register type in a target description
XML. The logic used for the extraction though is not sound:
unsigned field_len = TYPE_FIELD_BITSIZE (type, field);
ULONGEST field_val
= val >> (TYPE_FIELD_BITPOS (type, field) - field_len + 1);
TYPE_FIELD_BITSIZE: The bit length of the field to be extracted.
TYPE_FIELD_BITPOS: The starting position of the field; 0 is LSB.
val: The register value.
Imagine you have a field that starts at position 1 and its length
is 4 bits. According to the third line of the code snippet the
shifting right would become "val >> -2", or "val >> 0xfff...fe"
to be precise. That will result in a "field_val" of 0.
The correct extraction should be:
ULONGEST field_val = val >> TYPE_FIELD_BITPOS (type, field);
The rest of the algorithm that masks out the higher bits is OK.
Co-Authored-By: Simon Marchi <simon.marchi@efficios.com>
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=c9bd98593b785d9bf5f39c7aa74ed0226a23b830
---
gdb/valprint.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -40,6 +40,8 @@
#include "gdbarch.h"
#include "cli/cli-style.h"
#include "count-one-bits.h"
+#include "gdbsupport/selftest.h"
+#include "selftest-arch.h"
/* Maximum number of wchars returned from wchar_iterate. */
#define MAX_WCHARS 4
@@ -1157,8 +1159,7 @@
else
{
unsigned field_len = TYPE_FIELD_BITSIZE (type, field);
- ULONGEST field_val
- = val >> (TYPE_FIELD_BITPOS (type, field) - field_len + 1);
+ ULONGEST field_val = val >> TYPE_FIELD_BITPOS (type, field);
if (field_len < sizeof (ULONGEST) * TARGET_CHAR_BIT)
field_val &= ((ULONGEST) 1 << field_len) - 1;
@@ -3100,10 +3101,41 @@
return {{value_print_option_defs}, opts};
}
+#if GDB_SELF_TEST
+
+/* Test printing of TYPE_CODE_FLAGS values. */
+
+static void
+test_print_flags (gdbarch *arch)
+{
+ type *flags_type = arch_flags_type (arch, "test_type", 32);
+ type *field_type = builtin_type (arch)->builtin_uint32;
+
+ /* Value: 1010 1010
+ Fields: CCCB BAAA */
+ append_flags_type_field (flags_type, 0, 3, field_type, "A");
+ append_flags_type_field (flags_type, 3, 2, field_type, "B");
+ append_flags_type_field (flags_type, 5, 3, field_type, "C");
+
+ value *val = allocate_value (flags_type);
+ gdb_byte *contents = value_contents_writeable (val);
+ store_unsigned_integer (contents, 4, gdbarch_byte_order (arch), 0xaa);
+
+ string_file out;
+ val_print_type_code_flags (flags_type, val, 0, &out);
+ SELF_CHECK (out.string () == "[ A=2 B=1 C=5 ]");
+}
+
+#endif
+
void _initialize_valprint ();
void
_initialize_valprint ()
{
+#if GDB_SELF_TEST
+ selftests::register_test_foreach_arch ("print-flags", test_print_flags);
+#endif
+
cmd_list_element *cmd;
add_basic_prefix_cmd ("print", no_class,

View File

@ -0,0 +1,157 @@
From 440ea08bbf4c81f97852785642c6a6f18bdd28a9 Mon Sep 17 00:00:00 2001
From: Shahab Vahedi <shahab@synopsys.com>
Date: Mon, 19 Jul 2021 16:13:47 +0200
Subject: [PATCH 19/20] gdb: Make the builtin "boolean" type an unsigned type
When printing the fields of a register that is of a custom struct type,
the "unpack_bits_as_long ()" function is used:
do_val_print (...)
cp_print_value_fields (...)
value_field_bitfield (...)
unpack_value_bitfield (...)
unpack_bits_as_long (...)
This function may sign-extend the extracted field while returning it:
val >>= lsbcount;
if (...)
{
valmask = (((ULONGEST) 1) << bitsize) - 1;
val &= valmask;
if (!field_type->is_unsigned ())
if (val & (valmask ^ (valmask >> 1)))
val |= ~valmask;
}
return val;
lsbcount: Number of lower bits to get rid of.
bitsize: The bit length of the field to be extracted.
val: The register value.
field_type: The type of field that is being handled.
While the logic here is correct, there is a problem when it is
handling "field_type"s of "boolean". Those types are NOT marked
as "unsigned" and therefore they end up being sign extended.
Although this is not a problem for "false" (0), it definitely
causes trouble for "true".
This patch constructs the builtin boolean type as such that it is
marked as an "unsigned" entity.
The issue tackled here was first encountered for arc-elf32 target
running on an x86_64 machine. The unit-test introduced in this change
has passed for all the targets (--enable-targets=all) running on the
same x86_64 host.
Fixes: https://sourceware.org/PR28104
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=91254b918f1b35359d44b567a15013c42a931460
---
gdb/cp-valprint.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/gdbtypes.c | 2 -
2 files changed, 69 insertions(+), 1 deletion(-)
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -38,6 +38,8 @@
#include "gdbsupport/byte-vector.h"
#include "gdbarch.h"
#include "cli/cli-style.h"
+#include "gdbsupport/selftest.h"
+#include "selftest-arch.h"
static struct obstack dont_print_vb_obstack;
static struct obstack dont_print_statmem_obstack;
@@ -721,11 +723,77 @@
fprintf_filtered (stream, "%ld", (long) val);
}
+#if GDB_SELF_TEST
+
+/* Test printing of TYPE_CODE_STRUCT values. */
+
+static void
+test_print_fields (gdbarch *arch)
+{
+ struct field *f;
+ type *uint8_type = builtin_type (arch)->builtin_uint8;
+ type *bool_type = builtin_type (arch)->builtin_bool;
+ type *the_struct = arch_composite_type (arch, NULL, TYPE_CODE_STRUCT);
+ TYPE_LENGTH (the_struct) = 4;
+
+ /* Value: 1110 1001
+ Fields: C-BB B-A- */
+ if (gdbarch_byte_order (arch) == BFD_ENDIAN_LITTLE)
+ {
+ f = append_composite_type_field_raw (the_struct, "A", bool_type);
+ SET_FIELD_BITPOS (*f, 1);
+ FIELD_BITSIZE (*f) = 1;
+ f = append_composite_type_field_raw (the_struct, "B", uint8_type);
+ SET_FIELD_BITPOS (*f, 3);
+ FIELD_BITSIZE (*f) = 3;
+ f = append_composite_type_field_raw (the_struct, "C", bool_type);
+ SET_FIELD_BITPOS (*f, 7);
+ FIELD_BITSIZE (*f) = 1;
+ }
+ /* According to the logic commented in "make_gdb_type_struct ()" of
+ * target-descriptions.c, bit positions are numbered differently for
+ * little and big endians. */
+ else
+ {
+ f = append_composite_type_field_raw (the_struct, "A", bool_type);
+ SET_FIELD_BITPOS (*f, 30);
+ FIELD_BITSIZE (*f) = 1;
+ f = append_composite_type_field_raw (the_struct, "B", uint8_type);
+ SET_FIELD_BITPOS (*f, 26);
+ FIELD_BITSIZE (*f) = 3;
+ f = append_composite_type_field_raw (the_struct, "C", bool_type);
+ SET_FIELD_BITPOS (*f, 24);
+ FIELD_BITSIZE (*f) = 1;
+ }
+
+ value *val = allocate_value (the_struct);
+ gdb_byte *contents = value_contents_writeable (val);
+ store_unsigned_integer (contents, TYPE_LENGTH (value_enclosing_type (val)),
+ gdbarch_byte_order (arch), 0xe9);
+
+ string_file out;
+ struct value_print_options opts;
+ get_no_prettyformat_print_options (&opts);
+ cp_print_value_fields(val, &out, 0, &opts, NULL, 0);
+ SELF_CHECK (out.string () == "{A = false, B = 5, C = true}");
+
+ out.clear();
+ opts.format = 'x';
+ cp_print_value_fields(val, &out, 0, &opts, NULL, 0);
+ SELF_CHECK (out.string () == "{A = 0x0, B = 0x5, C = 0x1}");
+}
+
+#endif
+
void _initialize_cp_valprint ();
void
_initialize_cp_valprint ()
{
+#if GDB_SELF_TEST
+ selftests::register_test_foreach_arch ("print-fields", test_print_fields);
+#endif
+
obstack_begin (&dont_print_stat_array_obstack,
32 * sizeof (struct type *));
obstack_begin (&dont_print_statmem_obstack,
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5854,7 +5854,7 @@
builtin_type->builtin_string
= arch_type (gdbarch, TYPE_CODE_STRING, TARGET_CHAR_BIT, "string");
builtin_type->builtin_bool
- = arch_type (gdbarch, TYPE_CODE_BOOL, TARGET_CHAR_BIT, "bool");
+ = arch_boolean_type (gdbarch, TARGET_CHAR_BIT, 1, "bool");
/* The following three are about decimal floating point types, which
are 32-bits, 64-bits and 128-bits respectively. */

View File

@ -0,0 +1,40 @@
From 3f3e3620f54b17d6ba78046f45e05dffe2bf940d Mon Sep 17 00:00:00 2001
From: Shahab Vahedi <shahab@synopsys.com>
Date: Tue, 17 Aug 2021 16:39:26 +0200
Subject: [PATCH 20/20] opcodes: Fix the auxiliary register numbers for ARC HS
The numbers for the auxiliary registers "tlbindex" and
"tlbcommand" of ARCv2HS are incorrect. This patch makes
the following changes to correct that error.
,------------.-----------------.---------------.
| aux. reg. | old (incorrect) | new (correct) |
|------------+-----------------+---------------|
| tlbindex | 0x463 | 0x464 |
| tlbcommand | 0x464 | 0x465 |
`------------^-----------------^---------------'
opcodes/
2021-08-17 Shahab Vahedi <shahab@synopsys.com>
* arc-regs.h (DEF): Fix the register numbers.
Will be a part of GDB 11:
https://sourceware.org/git?p=binutils-gdb.git;a=commit;h=5d9cff510e8c04ded28272ef2121d814f5787a57
---
opcodes/arc-regs.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/opcodes/arc-regs.h
+++ b/opcodes/arc-regs.h
@@ -346,8 +346,8 @@
DEF (0x453, ARC_OPCODE_ARC600, NONE, pwr_ctrl)
DEF (0x460, ARC_OPCODE_ARCv2HS, NONE, tlbpd0)
DEF (0x461, ARC_OPCODE_ARCv2HS, NONE, tlbpd1)
-DEF (0x463, ARC_OPCODE_ARCv2HS, NONE, tlbindex)
-DEF (0x464, ARC_OPCODE_ARCv2HS, NONE, tlbcommand)
+DEF (0x464, ARC_OPCODE_ARCv2HS, NONE, tlbindex)
+DEF (0x465, ARC_OPCODE_ARCv2HS, NONE, tlbcommand)
DEF (0x468, ARC_OPCODE_ARCv2HS, NONE, pid)
DEF (0x46c, ARC_OPCODE_ARCv2HS, NONE, scratch_data0)
DEF (0x500, ARC_OPCODE_ARC700, NONE, aux_vlc_buf_idx)