From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by sourceware.org (Postfix) with ESMTP id B9474385840D for ; Thu, 20 Jan 2022 00:50:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B9474385840D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=loongson.cn Received: from localhost.localdomain (unknown [111.18.94.40]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9AxuuDIsehhEaoBAA--.6238S4; Thu, 20 Jan 2022 08:50:23 +0800 (CST) From: Tiezhu Yang To: gdb-patches@sourceware.org, Tom Tromey , Andrew Burgess Subject: [PATCH v2 2/5] gdb: LoongArch: Add initial baremetal support Date: Thu, 20 Jan 2022 08:50:08 +0800 Message-Id: <20220120005011.4531-3-yangtiezhu@loongson.cn> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20220120005011.4531-1-yangtiezhu@loongson.cn> References: <20220120005011.4531-1-yangtiezhu@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CM-TRANSID: AQAAf9AxuuDIsehhEaoBAA--.6238S4 X-Coremail-Antispam: 1UD129KBjvAXoW3uFWrAr1kKw4rCrW7ZF4DCFg_yoW8GryfXo WfuFsFqr1UGr18ZF4Fqr1DXFy8XFyYkrWxZ34fZF4DuF48ZrZ8G3y0ka15KFWftwnxJrWU Zay7twnxJFWxtF1rn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjp_UUUYk7k0a2IF6w4kM7kC6x804xWl14x267AKxVW8JVW5JwAFc2x0 x2IEx4CE42xK8VAvwI8IcIk0rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87 I2jVAFwI0_Jryl82xGYIkIc2x26xkF7I0E14v26r1I6r4UM28lY4IEw2IIxxk0rwA2F7IY 1VAKz4vEj48ve4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20x vEc7CjxVAFwI0_Gr0_Cr1l84ACjcxK6I8E87Iv67AKxVWxJr0_GcWl84ACjcxK6I8E87Iv 6xkF7I0E14v26F4UJVW0owAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzV Aqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S 6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JMxAIw28IcxkI7VAKI48JMxC20s026x CaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_ JrWlx4CE17CEb7AF67AKxVWUXVWUAwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r 1j6r1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVWUJVW8JwCI42IY6xAIw20EY4v20xvaj40_ Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVWUJVW8Jb IYCTnIWIevJa73UjIFyTuYvjxUgyEEUUUUU X-CM-SenderInfo: p1dqw3xlh2x3gn0dqz5rrqw2lrqou0/ X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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, 20 Jan 2022 00:50:29 -0000 This commit adds initial baremetal support for LoongArch. Signed-off-by: Zhensong Liu Signed-off-by: Qing zhang Signed-off-by: Youling Tang Signed-off-by: Tiezhu Yang --- gdb/loongarch-tdep.c | 316 +++++++++++++++++++++++++++++++++++++++++++ gdb/loongarch-tdep.h | 49 +++++++ 2 files changed, 365 insertions(+) create mode 100644 gdb/loongarch-tdep.c create mode 100644 gdb/loongarch-tdep.h diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c new file mode 100644 index 00000000000..ffcff03109a --- /dev/null +++ b/gdb/loongarch-tdep.c @@ -0,0 +1,316 @@ +/* Target-dependent code for the LoongArch architecture, for GDB. + + Copyright (C) 2022 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 . */ + +#include "defs.h" +#include "arch-utils.h" +#include "dwarf2/frame.h" +#include "elf-bfd.h" +#include "frame-unwind.h" +#include "loongarch-tdep.h" +#include "target-descriptions.h" +#include "trad-frame.h" +#include "user-regs.h" + +/* Implement the loongarch_skip_prologue gdbarch method. */ + +static CORE_ADDR +loongarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR func_addr; + + /* See if we can determine the end of the prologue via the symbol table. + If so, then return either PC, or the PC after the prologue, whichever + is greater. */ + if (find_pc_partial_function (pc, nullptr, &func_addr, nullptr)) + { + CORE_ADDR post_prologue_pc + = skip_prologue_using_sal (gdbarch, func_addr); + if (post_prologue_pc != 0) + return std::max (pc, post_prologue_pc); + } + + return 0; +} + +/* Adjust the address downward (direction of stack growth) so that it + is correctly aligned for a new stack frame. */ + +static CORE_ADDR +loongarch_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + return align_down (addr, 16); +} + +/* Generate, or return the cached frame cache for LoongArch frame unwinder. */ + +static struct trad_frame_cache * +loongarch_frame_cache (struct frame_info *this_frame, void **this_cache) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct trad_frame_cache *cache; + CORE_ADDR pc; + + if (*this_cache != nullptr) + return (struct trad_frame_cache *) *this_cache; + + cache = trad_frame_cache_zalloc (this_frame); + *this_cache = cache; + + loongarch_gdbarch_tdep *tdep = (loongarch_gdbarch_tdep *) gdbarch_tdep (gdbarch); + trad_frame_set_reg_realreg (cache, gdbarch_pc_regnum (gdbarch), tdep->regs.ra); + + pc = get_frame_address_in_block (this_frame); + trad_frame_set_id (cache, frame_id_build_unavailable_stack (pc)); + + return cache; +} + +/* Implement the this_id callback for LoongArch frame unwinder. */ + +static void +loongarch_frame_this_id (struct frame_info *this_frame, void **prologue_cache, + struct frame_id *this_id) +{ + struct trad_frame_cache *info; + + info = loongarch_frame_cache (this_frame, prologue_cache); + trad_frame_get_id (info, this_id); +} + +/* Implement the prev_register callback for LoongArch frame unwinder. */ + +static struct value * +loongarch_frame_prev_register (struct frame_info *this_frame, + void **prologue_cache, int regnum) +{ + struct trad_frame_cache *info; + + info = loongarch_frame_cache (this_frame, prologue_cache); + return trad_frame_get_register (info, this_frame, regnum); +} + +static const struct frame_unwind loongarch_frame_unwind = { + "loongarch prologue", + /*.type =*/NORMAL_FRAME, + /*.stop_reason =*/default_frame_unwind_stop_reason, + /*.this_id =*/loongarch_frame_this_id, + /*.prev_register =*/loongarch_frame_prev_register, + /*.unwind_data =*/nullptr, + /*.sniffer =*/default_frame_sniffer, + /*.dealloc_cache =*/nullptr, + /*.prev_arch =*/nullptr, +}; + +/* Implement the "dwarf2_reg_to_regnum" gdbarch method. */ + +static int +loongarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num) +{ + loongarch_gdbarch_tdep *tdep = (loongarch_gdbarch_tdep *) gdbarch_tdep (gdbarch); + auto regs = tdep->regs; + + if (0 <= num && num < 32) + return regs.r + num; + else + return -1; +} + +static constexpr gdb_byte loongarch_default_breakpoint[] = {0x05, 0x00, 0x2a, 0x00}; +typedef BP_MANIPULATION (loongarch_default_breakpoint) loongarch_breakpoint; + +/* Extract a set of required target features out of ABFD. If ABFD is nullptr + then a LOONGARCH_GDBARCH_FEATURES is returned in its default state. */ + +static struct loongarch_gdbarch_features +loongarch_features_from_bfd (const bfd *abfd) +{ + struct loongarch_gdbarch_features features; + + /* Now try to improve on the defaults by looking at the binary we are + going to execute. We assume the user knows what they are doing and + that the target will match the binary. Remember, this code path is + only used at all if the target hasn't given us a description, so this + is really a last ditched effort to do something sane before giving + up. */ + if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + unsigned char eclass = elf_elfheader (abfd)->e_ident[EI_CLASS]; + + if (eclass == ELFCLASS32) + features.xlen = 4; + else if (eclass == ELFCLASS64) + features.xlen = 8; + else + internal_error (__FILE__, __LINE__, + _("unknown ELF header class %d"), eclass); + } + + return features; +} + +/* Find a suitable default target description. Use the contents of INFO, + specifically the bfd object being executed, to guide the selection of a + suitable default target description. */ + +static const struct target_desc * +loongarch_find_default_target_description (const struct gdbarch_info info) +{ + /* Extract desired feature set from INFO. */ + struct loongarch_gdbarch_features features + = loongarch_features_from_bfd (info.abfd); + + /* If the XLEN field is still 0 then we got nothing useful from INFO.BFD, + maybe there was no bfd object. In this case we fall back to a minimal + useful target with no floating point, the x-register size is selected + based on the architecture from INFO. */ + if (features.xlen == 0) + features.xlen = info.bfd_arch_info->bits_per_address == 32 ? 4 : 8; + + /* Now build a target description based on the feature set. */ + return loongarch_lookup_target_description (features); +} + +/* Initialize the current architecture based on INFO */ + +static struct gdbarch * +loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + const struct target_desc *tdesc = info.target_desc; + + /* Ensure we always have a target description. */ + if (!tdesc_has_registers (tdesc)) + tdesc = loongarch_find_default_target_description (info); + + const struct tdesc_feature *feature_cpu + = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.base"); + if (feature_cpu == nullptr) + return nullptr; + + int xlen_bitsize = tdesc_register_bitsize (feature_cpu, "pc"); + struct loongarch_gdbarch_features features; + features.xlen = (xlen_bitsize / 8); + + size_t regnum = 0; + tdesc_arch_data_up tdesc_data = tdesc_data_alloc (); + loongarch_gdbarch_tdep *tdep = new loongarch_gdbarch_tdep; + tdep->regs.r = regnum; + + /* Validate the description provides the mandatory base registers + and allocate their numbers. */ + bool valid_p = true; + for (int i = 0; i < 32; i++) + valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), regnum++, + loongarch_r_normal_name[i] + 1); + valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), + tdep->regs.pc = regnum++, "pc"); + valid_p &= tdesc_numbered_register (feature_cpu, tdesc_data.get (), + tdep->regs.badv = regnum++, "badv"); + if (!valid_p) + return nullptr; + + /* LoongArch code is always little-endian. */ + info.byte_order_for_code = BFD_ENDIAN_LITTLE; + + /* Have a look at what the supplied (if any) bfd object requires of the + target, then check that this matches with what the target is + providing. */ + struct loongarch_gdbarch_features abi_features + = loongarch_features_from_bfd (info.abfd); + + /* If the ABI_FEATURES xlen is 0 then this indicates we got no useful abi + features from the INFO object. In this case we just treat the + hardware features as defining the abi. */ + if (abi_features.xlen == 0) + abi_features = features; + + /* Find a candidate among the list of pre-declared architectures. */ + for (arches = gdbarch_list_lookup_by_info (arches, &info); + arches != nullptr; + arches = gdbarch_list_lookup_by_info (arches->next, &info)) + { + /* Check that the feature set of the ARCHES matches the feature set + we are looking for. If it doesn't then we can't reuse this + gdbarch. */ + loongarch_gdbarch_tdep *candidate_tdep + = (loongarch_gdbarch_tdep *) gdbarch_tdep (arches->gdbarch); + + if (candidate_tdep->abi_features != abi_features) + continue; + + break; + } + + if (arches != nullptr) + return arches->gdbarch; + + /* None found, so create a new architecture from the information provided. */ + struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep); + tdep->abi_features = abi_features; + + /* Target data types. */ + set_gdbarch_short_bit (gdbarch, 16); + set_gdbarch_int_bit (gdbarch, 32); + set_gdbarch_long_bit (gdbarch, info.bfd_arch_info->bits_per_address); + set_gdbarch_long_long_bit (gdbarch, 64); + set_gdbarch_ptr_bit (gdbarch, info.bfd_arch_info->bits_per_address); + set_gdbarch_char_signed (gdbarch, 0); + + info.target_desc = tdesc; + info.tdesc_data = tdesc_data.get (); + + /* Information about registers. */ + tdep->regs.ra = tdep->regs.r + 1; + tdep->regs.sp = tdep->regs.r + 3; + set_gdbarch_num_regs (gdbarch, regnum); + set_gdbarch_sp_regnum (gdbarch, tdep->regs.sp); + set_gdbarch_pc_regnum (gdbarch, tdep->regs.pc); + + /* Finalise the target description registers. */ + tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data)); + + /* Advance PC across function entry code. */ + set_gdbarch_skip_prologue (gdbarch, loongarch_skip_prologue); + + /* Stack grows downward. */ + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + + /* Frame info. */ + set_gdbarch_frame_align (gdbarch, loongarch_frame_align); + + /* Breakpoint manipulation. */ + set_gdbarch_breakpoint_kind_from_pc (gdbarch, loongarch_breakpoint::kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, loongarch_breakpoint::bp_from_kind); + + /* Frame unwinders. Use DWARF debug info if available, otherwise use our own unwinder. */ + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, loongarch_dwarf2_reg_to_regnum); + dwarf2_append_unwinders (gdbarch); + frame_unwind_append_unwinder (gdbarch, &loongarch_frame_unwind); + + /* Hook in OS ABI-specific overrides, if they have been registered. */ + gdbarch_init_osabi (info, gdbarch); + + return gdbarch; +} + +void _initialize_loongarch_tdep (); +void +_initialize_loongarch_tdep () +{ + gdbarch_register (bfd_arch_loongarch, loongarch_gdbarch_init, nullptr); +} diff --git a/gdb/loongarch-tdep.h b/gdb/loongarch-tdep.h new file mode 100644 index 00000000000..b2fd16e25a7 --- /dev/null +++ b/gdb/loongarch-tdep.h @@ -0,0 +1,49 @@ +/* Target-dependent header for the LoongArch architecture, for GDB. + + Copyright (C) 2022 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 LOONGARCH_TDEP_H +#define LOONGARCH_TDEP_H + +#include "gdbarch.h" +#include "arch/loongarch.h" +#include "regset.h" + +#include "elf/loongarch.h" +#include "opcode/loongarch.h" + +/* Register set definitions. */ +extern const struct regset loongarch_gregset; + +/* Target-dependent structure in gdbarch. */ +struct loongarch_gdbarch_tdep : gdbarch_tdep +{ + /* Features about the abi that impact how the gdbarch is configured. */ + struct loongarch_gdbarch_features abi_features; + + struct + { + int r; /* General register. */ + int ra; /* Return Address. */ + int sp; /* Stack Pointer. */ + int pc; /* Program Counter. */ + int badv; /* Bad vaddr for addressing exception. */ + } regs; /* LoongArch registers */ +}; + +#endif /* LOONGARCH_TDEP_H */ -- 2.27.0