From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x643.google.com (mail-ej1-x643.google.com [IPv6:2a00:1450:4864:20::643]) by sourceware.org (Postfix) with ESMTPS id 96977384607A for ; Thu, 27 Aug 2020 11:27:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 96977384607A Received: by mail-ej1-x643.google.com with SMTP id bo3so7124083ejb.11 for ; Thu, 27 Aug 2020 04:27:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=+gBqyxCSz+z1WpkNoaPMNQo4PKV7lcrbwoK8cTnrn8A=; b=guO8Hd59i/OncnSBOeQ3HMisCnHMfBnrgrsajENuQi8KX+MY4Q0JKHvb9Nf3JpGknH j4CYPXCEefqYVyL1gUXidavgkOTghpMTNCcpi5CxbuXThSk56dYHjxJqGAE4WcZ28Xi9 UTxQAL/zUROI6VeskH/3NLLYYdQv0l0tWUWOmmZJNIaMTy8buKwUPno3Eaw5ZnOlecoQ ky5g2yNePO+7Th/YZvuq6OuxRXLO6b0rMQgMj2gbyGryQ4d9/y0Mnkc4vTucrLacIXkc gH49tcEsFri8ks5N4dMhhjTb2udixhuFk8CiF6rpFwyUC0oB2VlC/xXwsIyGFePEQtu2 AB3w== X-Gm-Message-State: AOAM531HxvjdlIpaAeEm/W/plosL7FupFOUnUG7ZLwTUg/vO0ZWWzjDL 8iya/QU0IYXRBTGBaFGtL+XWmfTnyteLhguI X-Google-Smtp-Source: ABdhPJxbEb9Q3nL0g5cLTfGUlDvWN0ftxk8c4flhl4am+oUcLGy+QxfJ6CvkPxYrZ83tKXZOhOD4YQ== X-Received: by 2002:a17:906:3acb:: with SMTP id z11mr19390412ejd.530.1598527646201; Thu, 27 Aug 2020 04:27:26 -0700 (PDT) Received: from atlantis.home ([2a03:1b20:3:f011::6d]) by smtp.gmail.com with ESMTPSA id a26sm1663118eju.83.2020.08.27.04.27.24 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 27 Aug 2020 04:27:25 -0700 (PDT) From: Shahab Vahedi To: gdb-patches@sourceware.org Cc: Shahab Vahedi , Shahab Vahedi , Francois Bedard , Anton Kolesov Subject: [PATCH] arc: Add support for Linux coredump files Date: Thu, 27 Aug 2020 13:27:28 +0200 Message-Id: <20200827112728.4275-1-shahab.vahedi@gmail.com> X-Mailer: git-send-email 2.28.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 27 Aug 2020 11:27:29 -0000 From: Anton Kolesov 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]. [1] arc: Add support for ARC HS extra registers in core files https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=2745674244d6aecddcf636475034bdb9c0a6b4a0 gdb/ChangeLog: Anton Kolesov * 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.c (ARC_OFFSET_NO_REGISTER): Declare. --- gdb/arc-linux-tdep.c | 193 +++++++++++++++++++++++++++++++++++++++++++ gdb/arc-linux-tdep.h | 52 ++++++++++++ gdb/arc-tdep.c | 5 +- gdb/arc-tdep.h | 8 ++ 4 files changed, 255 insertions(+), 3 deletions(-) create mode 100644 gdb/arc-linux-tdep.h diff --git a/gdb/arc-linux-tdep.c b/gdb/arc-linux-tdep.c index 36f32459bbe..8dcd9785458 100644 --- a/gdb/arc-linux-tdep.c +++ b/gdb/arc-linux-tdep.c @@ -27,7 +27,61 @@ /* 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. */ + +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 */ +}; /* Implement the "cannot_fetch_register" gdbarch method. */ @@ -227,6 +281,142 @@ 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)) + { + int eret_offset = REGOFF (6); + regcache->raw_collect (regnum, buf + eret_offset); + } + else + 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 (!"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_gdbarch_features features + = arc_gdbarch_features_create (abfd, + gdbarch_bfd_arch_info (gdbarch)->mach); + return arc_lookup_target_description (features); +} + /* Initialization specific to Linux environment. */ static void @@ -260,6 +450,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). */ diff --git a/gdb/arc-linux-tdep.h b/gdb/arc-linux-tdep.h new file mode 100644 index 00000000000..c26cacd7029 --- /dev/null +++ b/gdb/arc-linux-tdep.h @@ -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 . */ + +#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 */ diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c index 6f544bff78d..91e106a0167 100644 --- a/gdb/arc-tdep.c +++ b/gdb/arc-tdep.c @@ -1883,10 +1883,9 @@ mach_type_to_arc_isa (const unsigned long mach) } } -/* Common construction code for ARC_GDBARCH_FEATURES struct. If there - is no ABFD, then a FEATURE with default values is returned. */ +/* See arc-tdep.h. */ -static arc_gdbarch_features +arc_gdbarch_features arc_gdbarch_features_create (const bfd *abfd, const unsigned long mach) { /* Use 4 as a fallback value. */ diff --git a/gdb/arc-tdep.h b/gdb/arc-tdep.h index 6331d29f402..d8a0c42909d 100644 --- a/gdb/arc-tdep.h +++ b/gdb/arc-tdep.h @@ -105,6 +105,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 +185,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_gdbarch_features instance from the provided data. */ + +arc_gdbarch_features arc_gdbarch_features_create (const bfd *abfd, + const unsigned long mach); + #endif /* ARC_TDEP_H */ -- 2.28.0