Don't close thread handles provided by WaitForDebugEvent
[deliverable/binutils-gdb.git] / gdb / riscv-linux-tdep.c
index d072c0b754f9d7cd956ce44b59bf3776d06d9837..12c0eef223cb9ade3ef6378e8cfaa412868e97f6 100644 (file)
@@ -1,5 +1,5 @@
 /* Target-dependent code for GNU/Linux on RISC-V processors.
-   Copyright (C) 2018 Free Software Foundation, Inc.
+   Copyright (C) 2018-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -23,6 +23,9 @@
 #include "linux-tdep.h"
 #include "solib-svr4.h"
 #include "regset.h"
+#include "tramp-frame.h"
+#include "trad-frame.h"
+#include "gdbarch.h"
 
 /* Define the general register mapping.  The kernel puts the PC at offset 0,
    gdb puts it at offset 32.  Register x0 is always 0 and can be ignored.
@@ -35,6 +38,16 @@ static const struct regcache_map_entry riscv_linux_gregmap[] =
   { 0 }
 };
 
+/* Define the FP register mapping.  The kernel puts the 32 FP regs first, and
+   then FCSR.  */
+
+static const struct regcache_map_entry riscv_linux_fregmap[] =
+{
+  { 32, RISCV_FIRST_FP_REGNUM, 0 },
+  { 1, RISCV_CSR_FCSR_REGNUM, 0 },
+  { 0 }
+};
+
 /* Define the general register regset.  */
 
 static const struct regset riscv_linux_gregset =
@@ -42,6 +55,13 @@ static const struct regset riscv_linux_gregset =
   riscv_linux_gregmap, regcache_supply_regset, regcache_collect_regset
 };
 
+/* Define the FP register regset.  */
+
+static const struct regset riscv_linux_fregset =
+{
+  riscv_linux_fregmap, regcache_supply_regset, regcache_collect_regset
+};
+
 /* Define hook for core file support.  */
 
 static void
@@ -52,8 +72,86 @@ riscv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
 {
   cb (".reg", (32 * riscv_isa_xlen (gdbarch)), (32 * riscv_isa_xlen (gdbarch)),
       &riscv_linux_gregset, NULL, cb_data);
+  /* The kernel is adding 8 bytes for FCSR.  */
+  cb (".reg2", (32 * riscv_isa_flen (gdbarch)) + 8,
+      (32 * riscv_isa_flen (gdbarch)) + 8,
+      &riscv_linux_fregset, NULL, cb_data);
+}
+
+/* Signal trampoline support.  */
+
+static void riscv_linux_sigframe_init (const struct tramp_frame *self,
+                                      struct frame_info *this_frame,
+                                      struct trad_frame_cache *this_cache,
+                                      CORE_ADDR func);
+
+#define RISCV_INST_LI_A7_SIGRETURN     0x08b00893
+#define RISCV_INST_ECALL               0x00000073
+
+static const struct tramp_frame riscv_linux_sigframe = {
+  SIGTRAMP_FRAME,
+  4,
+  {
+    { RISCV_INST_LI_A7_SIGRETURN, ULONGEST_MAX },
+    { RISCV_INST_ECALL, ULONGEST_MAX },
+    { TRAMP_SENTINEL_INSN }
+  },
+  riscv_linux_sigframe_init,
+  NULL
+};
+
+/* Runtime signal frames look like this:
+   struct rt_sigframe {
+     struct siginfo info;
+     struct ucontext uc;
+   };
+
+   struct ucontext {
+     unsigned long __uc_flags;
+     struct ucontext *uclink;
+     stack_t uc_stack;
+     sigset_t uc_sigmask;
+     char __glibc_reserved[1024 / 8 - sizeof (sigset_t)];
+     mcontext_t uc_mcontext;
+   }; */
 
-  /* TODO: Add FP register support.  */
+#define SIGFRAME_SIGINFO_SIZE          128
+#define UCONTEXT_MCONTEXT_OFFSET       176
+
+static void
+riscv_linux_sigframe_init (const struct tramp_frame *self,
+                          struct frame_info *this_frame,
+                          struct trad_frame_cache *this_cache,
+                          CORE_ADDR func)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  int xlen = riscv_isa_xlen (gdbarch);
+  int flen = riscv_isa_flen (gdbarch);
+  CORE_ADDR frame_sp = get_frame_sp (this_frame);
+  CORE_ADDR mcontext_base;
+  CORE_ADDR regs_base;
+
+  mcontext_base = frame_sp + SIGFRAME_SIGINFO_SIZE + UCONTEXT_MCONTEXT_OFFSET;
+
+  /* Handle the integer registers.  The first one is PC, followed by x1
+     through x31.  */
+  regs_base = mcontext_base;
+  trad_frame_set_reg_addr (this_cache, RISCV_PC_REGNUM, regs_base);
+  for (int i = 1; i < 32; i++)
+    trad_frame_set_reg_addr (this_cache, RISCV_ZERO_REGNUM + i,
+                            regs_base + (i * xlen));
+
+  /* Handle the FP registers.  First comes the 32 FP registers, followed by
+     fcsr.  */
+  regs_base += 32 * xlen;
+  for (int i = 0; i < 32; i++)
+    trad_frame_set_reg_addr (this_cache, RISCV_FIRST_FP_REGNUM + i,
+                            regs_base + (i * flen));
+  regs_base += 32 * flen;
+  trad_frame_set_reg_addr (this_cache, RISCV_CSR_FCSR_REGNUM, regs_base);
+
+  /* Choice of the bottom of the sigframe is somewhat arbitrary.  */
+  trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
 }
 
 /* Initialize RISC-V Linux ABI info.  */
@@ -82,12 +180,15 @@ riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   set_gdbarch_iterate_over_regset_sections
     (gdbarch, riscv_linux_iterate_over_regset_sections);
+
+  tramp_frame_prepend_unwinder (gdbarch, &riscv_linux_sigframe);
 }
 
 /* Initialize RISC-V Linux target support.  */
 
+void _initialize_riscv_linux_tdep ();
 void
-_initialize_riscv_linux_tdep (void)
+_initialize_riscv_linux_tdep ()
 {
   gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_LINUX,
                          riscv_linux_init_abi);
This page took 0.025215 seconds and 4 git commands to generate.