arc: Add support for Linux coredump files
With the implemenations in this patch, ARC gdb can handle coredump related matters. The binutils counter part of this patch has already been pushed [1]. v2 [2]: - arc_linux_collect_gregset: Use "reg <= ARC_LAST_REGNUM" instead of "reg < ARC_LAST_REGNUM" for the condition check of the for-loop. - arc-linux-tdep.c: Use "ARC_LAST_REGNUM < ARRAY_SIZE (...)" instead of "ARC_LAST_REGNUM <= ARRAY_SIZE (...)" for the "asserts". - Use "buf + arc_linux_core_reg_offsets[ARC_ERET_REGNUM]" instead of "buf + REG_OFF (6)". - Fix a few typos/indentation. v3 [3]: - Use gdb_assert_not_reached(text) instead of gdb_assert (!text). - Remove unnecessary braces in the for loop. [1] arc: Add support for ARC HS extra registers in core files https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=2745674244d6aecddcf636475034bdb9c0a6b4a0 [2] First remarks https://sourceware.org/pipermail/gdb-patches/2020-September/171912.html [3] Second remarks https://sourceware.org/pipermail/gdb-patches/2020-October/172302.html gdb/ChangeLog: * arc-linux-tdep.h: New file. * arc-linux-tdep.c (arc_linux_core_reg_offsets, arc_linux_supply_gregset, arc_linux_supply_v2_regset, arc_linux_collect_gregset, arc_linux_collect_v2_regset, arc_linux_gregset, arc_linux_v2_regset, arc_linux_iterate_over_regset_sections, arc_linux_core_read_description): Implement. (arc_linux_init_osabi): Set iterate_over_regset_sections. * arc-tdep.h (ARC_OFFSET_NO_REGISTER): Declare. (arc_gdbarch_features_create): Add. * arc-tdep.c (arc_gdbarch_features_create): Not static anymore.
This commit is contained in:
parent
6d2d7c5668
commit
cc463201c4
5 changed files with 270 additions and 4 deletions
|
@ -1,3 +1,17 @@
|
|||
2020-10-07 Anton Kolesov <anton.kolesov@synopsys.com>
|
||||
|
||||
* arc-linux-tdep.h: New file.
|
||||
* arc-linux-tdep.c (arc_linux_core_reg_offsets,
|
||||
arc_linux_supply_gregset, arc_linux_supply_v2_regset,
|
||||
arc_linux_collect_gregset, arc_linux_collect_v2_regset,
|
||||
arc_linux_gregset, arc_linux_v2_regset,
|
||||
arc_linux_iterate_over_regset_sections,
|
||||
arc_linux_core_read_description): Implement.
|
||||
(arc_linux_init_osabi): Set iterate_over_regset_sections.
|
||||
* arc-tdep.h (ARC_OFFSET_NO_REGISTER): Declare.
|
||||
(arc_gdbarch_features_create): Add.
|
||||
* arc-tdep.c (arc_gdbarch_features_create): Not static anymore.
|
||||
|
||||
2020-10-07 Shahab Vahedi <shahab@synopsys.com>
|
||||
|
||||
* arch/arc.h: Rename "arc_gdbarch_features" to
|
||||
|
|
|
@ -27,7 +27,65 @@
|
|||
|
||||
/* ARC header files. */
|
||||
#include "opcodes/arc-dis.h"
|
||||
#include "arc-linux-tdep.h"
|
||||
#include "arc-tdep.h"
|
||||
#include "arch/arc.h"
|
||||
|
||||
#define REGOFF(offset) (offset * ARC_REGISTER_SIZE)
|
||||
|
||||
/* 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.
|
||||
|
||||
From include/uapi/asm/ptrace.h in the ARC Linux sources. */
|
||||
|
||||
/* 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_core_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. */
|
||||
REGOFF (37), REGOFF (36), REGOFF (35), REGOFF (34),
|
||||
REGOFF (33), REGOFF (32), REGOFF (31), REGOFF (30),
|
||||
REGOFF (29), REGOFF (28), REGOFF (27), REGOFF (26),
|
||||
REGOFF (25),
|
||||
|
||||
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 (39), /* PC */
|
||||
REGOFF (5), /* STATUS32 */
|
||||
REGOFF (2), /* LP_START */
|
||||
REGOFF (3), /* LP_END */
|
||||
REGOFF (1), /* BTA */
|
||||
REGOFF (6) /* ERET */
|
||||
};
|
||||
|
||||
/* Implement the "cannot_fetch_register" gdbarch method. */
|
||||
|
||||
|
@ -227,6 +285,136 @@ arc_linux_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
arc_linux_supply_gregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *gregs, size_t size)
|
||||
{
|
||||
gdb_static_assert (ARC_LAST_REGNUM
|
||||
< ARRAY_SIZE (arc_linux_core_reg_offsets));
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
void
|
||||
arc_linux_supply_v2_regset (const struct regset *regset,
|
||||
struct regcache *regcache, int regnum,
|
||||
const void *v2_regs, size_t size)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
/* Populate BUF with register REGNUM from the REGCACHE. */
|
||||
|
||||
static void
|
||||
collect_register (const struct regcache *regcache, struct gdbarch *gdbarch,
|
||||
int regnum, gdb_byte *buf)
|
||||
{
|
||||
/* Skip non-existing registers. */
|
||||
if ((arc_linux_core_reg_offsets[regnum] == ARC_OFFSET_NO_REGISTER))
|
||||
return;
|
||||
|
||||
/* The address where the execution has stopped is in pseudo-register
|
||||
STOP_PC. However, when kernel code is returning from the exception,
|
||||
it uses the value from ERET register. Since, TRAP_S (the breakpoint
|
||||
instruction) commits, the ERET points to the next instruction. In
|
||||
other words: ERET != STOP_PC. To jump back from the kernel code to
|
||||
the correct address, ERET must be overwritten by GDB's STOP_PC. Else,
|
||||
the program will continue at the address after the current instruction.
|
||||
*/
|
||||
if (regnum == gdbarch_pc_regnum (gdbarch))
|
||||
regnum = ARC_ERET_REGNUM;
|
||||
regcache->raw_collect (regnum, buf + arc_linux_core_reg_offsets[regnum]);
|
||||
}
|
||||
|
||||
void
|
||||
arc_linux_collect_gregset (const struct regset *regset,
|
||||
const struct regcache *regcache,
|
||||
int regnum, void *gregs, size_t size)
|
||||
{
|
||||
gdb_static_assert (ARC_LAST_REGNUM
|
||||
< ARRAY_SIZE (arc_linux_core_reg_offsets));
|
||||
|
||||
gdb_byte *buf = (gdb_byte *) gregs;
|
||||
struct gdbarch *gdbarch = regcache->arch ();
|
||||
|
||||
/* 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);
|
||||
else if (regnum <= ARC_LAST_REGNUM)
|
||||
collect_register (regcache, gdbarch, regnum, buf);
|
||||
else
|
||||
gdb_assert_not_reached ("Invalid regnum in arc_linux_collect_gregset.");
|
||||
}
|
||||
|
||||
void
|
||||
arc_linux_collect_v2_regset (const struct regset *regset,
|
||||
const struct regcache *regcache, int regnum,
|
||||
void *v2_regs, size_t size)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
/* Linux regset definitions. */
|
||||
|
||||
static const struct regset arc_linux_gregset = {
|
||||
arc_linux_core_reg_offsets,
|
||||
arc_linux_supply_gregset,
|
||||
arc_linux_collect_gregset,
|
||||
};
|
||||
|
||||
static const struct regset arc_linux_v2_regset = {
|
||||
NULL,
|
||||
arc_linux_supply_v2_regset,
|
||||
arc_linux_collect_v2_regset,
|
||||
};
|
||||
|
||||
/* Implement the `iterate_over_regset_sections` gdbarch method. */
|
||||
|
||||
static void
|
||||
arc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
|
||||
iterate_over_regset_sections_cb *cb,
|
||||
void *cb_data,
|
||||
const struct regcache *regcache)
|
||||
{
|
||||
/* There are 40 registers in Linux user_regs_struct, although some of
|
||||
them are now just a mere paddings, kept to maintain binary
|
||||
compatibility with older tools. */
|
||||
const int sizeof_gregset = 40 * ARC_REGISTER_SIZE;
|
||||
|
||||
cb (".reg", sizeof_gregset, sizeof_gregset, &arc_linux_gregset, NULL,
|
||||
cb_data);
|
||||
cb (".reg-arc-v2", ARC_LINUX_SIZEOF_V2_REGSET, ARC_LINUX_SIZEOF_V2_REGSET,
|
||||
&arc_linux_v2_regset, NULL, cb_data);
|
||||
}
|
||||
|
||||
/* Implement the `core_read_description` gdbarch method. */
|
||||
|
||||
static const struct target_desc *
|
||||
arc_linux_core_read_description (struct gdbarch *gdbarch,
|
||||
struct target_ops *target,
|
||||
bfd *abfd)
|
||||
{
|
||||
arc_arch_features features
|
||||
= arc_arch_features_create (abfd,
|
||||
gdbarch_bfd_arch_info (gdbarch)->mach);
|
||||
return arc_lookup_target_description (features);
|
||||
}
|
||||
|
||||
/* Initialization specific to Linux environment. */
|
||||
|
||||
static void
|
||||
|
@ -260,6 +448,9 @@ arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
|||
set_gdbarch_software_single_step (gdbarch, arc_linux_software_single_step);
|
||||
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
|
||||
set_gdbarch_skip_solib_resolver (gdbarch, arc_linux_skip_solib_resolver);
|
||||
set_gdbarch_iterate_over_regset_sections
|
||||
(gdbarch, arc_linux_iterate_over_regset_sections);
|
||||
set_gdbarch_core_read_description (gdbarch, arc_linux_core_read_description);
|
||||
|
||||
/* GNU/Linux uses SVR4-style shared libraries, with 32-bit ints, longs
|
||||
and pointers (ILP32). */
|
||||
|
|
52
gdb/arc-linux-tdep.h
Normal file
52
gdb/arc-linux-tdep.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* Target 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/>. */
|
||||
|
||||
#ifndef ARC_LINUX_TDEP_H
|
||||
#define ARC_LINUX_TDEP_H
|
||||
|
||||
#include "gdbarch.h"
|
||||
#include "regset.h"
|
||||
|
||||
#define ARC_LINUX_SIZEOF_V2_REGSET (3 * ARC_REGISTER_SIZE)
|
||||
|
||||
/* Reads registers from the NT_PRSTATUS data array into the regcache. */
|
||||
|
||||
void arc_linux_supply_gregset (const struct regset *regset,
|
||||
struct regcache *regcache, int regnum,
|
||||
const void *gregs, size_t size);
|
||||
|
||||
/* Reads regsiters from the NT_ARC_V2 data array into the regcache. */
|
||||
|
||||
void arc_linux_supply_v2_regset (const struct regset *regset,
|
||||
struct regcache *regcache, int regnum,
|
||||
const void *v2_regs, size_t size);
|
||||
|
||||
/* Writes registers from the regcache into the NT_PRSTATUS data array. */
|
||||
|
||||
void arc_linux_collect_gregset (const struct regset *regset,
|
||||
const struct regcache *regcache,
|
||||
int regnum, void *gregs, size_t size);
|
||||
|
||||
/* Writes registers from the regcache into the NT_ARC_V2 data array. */
|
||||
|
||||
void arc_linux_collect_v2_regset (const struct regset *regset,
|
||||
const struct regcache *regcache,
|
||||
int regnum, void *v2_regs, size_t size);
|
||||
|
||||
#endif /* ARC_LINUX_TDEP_H */
|
|
@ -1883,10 +1883,9 @@ mach_type_to_arc_isa (const unsigned long mach)
|
|||
}
|
||||
}
|
||||
|
||||
/* Common construction code for ARC_ARCH_FEATURES struct. If there
|
||||
is no ABFD, then a FEATURE with default values is returned. */
|
||||
/* See arc-tdep.h. */
|
||||
|
||||
static arc_arch_features
|
||||
arc_arch_features
|
||||
arc_arch_features_create (const bfd *abfd, const unsigned long mach)
|
||||
{
|
||||
/* Use 4 as a fallback value. */
|
||||
|
|
|
@ -85,7 +85,9 @@ enum arc_regnum
|
|||
ARC_LP_END_REGNUM,
|
||||
/* Branch target address. */
|
||||
ARC_BTA_REGNUM,
|
||||
ARC_LAST_AUX_REGNUM = ARC_BTA_REGNUM,
|
||||
/* Exception return address. */
|
||||
ARC_ERET_REGNUM,
|
||||
ARC_LAST_AUX_REGNUM = ARC_ERET_REGNUM,
|
||||
ARC_LAST_REGNUM = ARC_LAST_AUX_REGNUM,
|
||||
|
||||
/* Additional ABI constants. */
|
||||
|
@ -105,6 +107,9 @@ enum arc_regnum
|
|||
/* STATUS32 register: current instruction is a delay slot. */
|
||||
#define ARC_STATUS32_DE_MASK (1 << 6)
|
||||
|
||||
/* Special value for register offset arrays. */
|
||||
#define ARC_OFFSET_NO_REGISTER (-1)
|
||||
|
||||
#define arc_print(fmt, args...) fprintf_unfiltered (gdb_stdlog, fmt, ##args)
|
||||
|
||||
extern int arc_debug;
|
||||
|
@ -182,4 +187,9 @@ CORE_ADDR arc_insn_get_branch_target (const struct arc_instruction &insn);
|
|||
|
||||
CORE_ADDR arc_insn_get_linear_next_pc (const struct arc_instruction &insn);
|
||||
|
||||
/* Create an arc_arch_features instance from the provided data. */
|
||||
|
||||
arc_arch_features arc_arch_features_create (const bfd *abfd,
|
||||
const unsigned long mach);
|
||||
|
||||
#endif /* ARC_TDEP_H */
|
||||
|
|
Loading…
Add table
Reference in a new issue