public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tiezhu Yang <yangtiezhu@loongson.cn>
To: gdb-patches@sourceware.org, Tom Tromey <tom@tromey.com>,
	Andrew Burgess <aburgess@redhat.com>
Subject: [PATCH v2 2/5] gdb: LoongArch: Add initial baremetal support
Date: Thu, 20 Jan 2022 08:50:08 +0800	[thread overview]
Message-ID: <20220120005011.4531-3-yangtiezhu@loongson.cn> (raw)
In-Reply-To: <20220120005011.4531-1-yangtiezhu@loongson.cn>

This commit adds initial baremetal support for LoongArch.

Signed-off-by: Zhensong Liu <liuzhensong@loongson.cn>
Signed-off-by: Qing zhang <zhangqing@loongson.cn>
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
---
 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 <http://www.gnu.org/licenses/>.  */
+
+#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 <http://www.gnu.org/licenses/>.  */
+
+#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


  parent reply	other threads:[~2022-01-20  0:50 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-20  0:50 [PATCH v2 0/5] gdb: Add basic support for LoongArch Tiezhu Yang
2022-01-20  0:50 ` [PATCH v2 1/5] gdb: LoongArch: Add initial target description support Tiezhu Yang
2022-01-20  0:50 ` Tiezhu Yang [this message]
2022-01-20  0:50 ` [PATCH v2 3/5] gdb: LoongArch: Add initial Linux target support Tiezhu Yang
2022-01-20  0:50 ` [PATCH v2 4/5] gdb: LoongArch: Add initial native Linux support Tiezhu Yang
2022-01-20  0:50 ` [PATCH v2 5/5] gdb: LoongArch: Add Makefile, configure and NEWS Tiezhu Yang
2022-02-08  4:45 ` [PING] [PATCH v2 0/5] gdb: Add basic support for LoongArch Tiezhu Yang
2022-02-10 19:57   ` Tom Tromey
2022-02-11 12:50     ` Tiezhu Yang
2022-02-11 13:40 ` Simon Marchi
2022-02-12  7:59   ` Tiezhu Yang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220120005011.4531-3-yangtiezhu@loongson.cn \
    --to=yangtiezhu@loongson.cn \
    --cc=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=tom@tromey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).