Submitted By: Bruce Dubbs <bdubbs AT linuxfromscratch.org DOT org>
Date: 2022-02-06
Initial Package Version: 11.2
Origin: Upstream GIT Repository
Description: Fix gdb to be compatible with glibc-2.35

diff -Naur gdb-11.2.orig/gdb/aarch64-linux-tdep.c gdb-11.2/gdb/aarch64-linux-tdep.c
--- gdb-11.2.orig/gdb/aarch64-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/aarch64-linux-tdep.c	2022-02-06 14:36:56.655215646 -0600
@@ -1795,7 +1795,7 @@
   linux_init_abi (info, gdbarch, 1);
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_lp64_fetch_link_map_offsets);
+					 linux_lp64_fetch_link_map_offsets);
 
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
diff -Naur gdb-11.2.orig/gdb/alpha-linux-tdep.c gdb-11.2/gdb/alpha-linux-tdep.c
--- gdb-11.2.orig/gdb/alpha-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/alpha-linux-tdep.c	2022-02-06 14:36:56.655215646 -0600
@@ -374,7 +374,7 @@
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
 
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_lp64_fetch_link_map_offsets);
+    (gdbarch, linux_lp64_fetch_link_map_offsets);
 
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
diff -Naur gdb-11.2.orig/gdb/amd64-linux-tdep.c gdb-11.2/gdb/amd64-linux-tdep.c
--- gdb-11.2.orig/gdb/amd64-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/amd64-linux-tdep.c	2022-02-06 14:36:56.655215646 -0600
@@ -2042,7 +2042,7 @@
 
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_lp64_fetch_link_map_offsets);
+    (gdbarch, linux_lp64_fetch_link_map_offsets);
 
   /* Register DTrace handlers.  */
   set_gdbarch_dtrace_parse_probe_argument (gdbarch, amd64_dtrace_parse_probe_argument);
@@ -2256,7 +2256,7 @@
 
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 }
 
 void _initialize_amd64_linux_tdep ();
diff -Naur gdb-11.2.orig/gdb/arc-linux-tdep.c gdb-11.2/gdb/arc-linux-tdep.c
--- gdb-11.2.orig/gdb/arc-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/arc-linux-tdep.c	2022-02-06 14:36:56.656215655 -0600
@@ -732,7 +732,7 @@
   /* GNU/Linux uses SVR4-style shared libraries, with 32-bit ints, longs
      and pointers (ILP32).  */
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_ilp32_fetch_link_map_offsets);
+					 linux_ilp32_fetch_link_map_offsets);
 }
 
 /* Suppress warning from -Wmissing-prototypes.  */
diff -Naur gdb-11.2.orig/gdb/arm-linux-tdep.c gdb-11.2/gdb/arm-linux-tdep.c
--- gdb-11.2.orig/gdb/arm-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/arm-linux-tdep.c	2022-02-06 14:36:56.656215655 -0600
@@ -1763,7 +1763,7 @@
   tdep->jb_elt_size = ARM_LINUX_JB_ELEMENT_SIZE;
 
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 
   /* Single stepping.  */
   set_gdbarch_software_single_step (gdbarch, arm_linux_software_single_step);
diff -Naur gdb-11.2.orig/gdb/cris-linux-tdep.c gdb-11.2/gdb/cris-linux-tdep.c
--- gdb-11.2.orig/gdb/cris-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/cris-linux-tdep.c	2022-02-06 14:36:56.657215664 -0600
@@ -43,7 +43,7 @@
 					       svr4_fetch_objfile_link_map);
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_ilp32_fetch_link_map_offsets);
+					 linux_ilp32_fetch_link_map_offsets);
 
 }
 
diff -Naur gdb-11.2.orig/gdb/csky-linux-tdep.c gdb-11.2/gdb/csky-linux-tdep.c
--- gdb-11.2.orig/gdb/csky-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/csky-linux-tdep.c	2022-02-06 14:36:56.657215664 -0600
@@ -239,7 +239,7 @@
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_ilp32_fetch_link_map_offsets);
+					 linux_ilp32_fetch_link_map_offsets);
 
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
diff -Naur gdb-11.2.orig/gdb/hppa-linux-tdep.c gdb-11.2/gdb/hppa-linux-tdep.c
--- gdb-11.2.orig/gdb/hppa-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/hppa-linux-tdep.c	2022-02-06 14:36:56.657215664 -0600
@@ -501,7 +501,7 @@
 
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 
   tdep->in_solib_call_trampoline = hppa_in_solib_call_trampoline;
   set_gdbarch_skip_trampoline_code (gdbarch, hppa_skip_trampoline_code);
diff -Naur gdb-11.2.orig/gdb/i386-linux-tdep.c gdb-11.2/gdb/i386-linux-tdep.c
--- gdb-11.2.orig/gdb/i386-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/i386-linux-tdep.c	2022-02-06 14:36:56.657215664 -0600
@@ -1044,7 +1044,7 @@
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 
   /* GNU/Linux uses the dynamic linker included in the GNU C Library.  */
   set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
diff -Naur gdb-11.2.orig/gdb/ia64-linux-tdep.c gdb-11.2/gdb/ia64-linux-tdep.c
--- gdb-11.2.orig/gdb/ia64-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/ia64-linux-tdep.c	2022-02-06 14:36:56.657215664 -0600
@@ -237,7 +237,7 @@
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
 
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_lp64_fetch_link_map_offsets);
+    (gdbarch, linux_lp64_fetch_link_map_offsets);
 
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
diff -Naur gdb-11.2.orig/gdb/linux-tdep.c gdb-11.2/gdb/linux-tdep.c
--- gdb-11.2.orig/gdb/linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/linux-tdep.c	2022-02-06 14:36:56.658215673 -0600
@@ -41,6 +41,7 @@
 #include "gdbsupport/gdb_optional.h"
 #include "gcore.h"
 #include "gcore-elf.h"
+#include "solib-svr4.h"
 
 #include <ctype.h>
 
@@ -2725,3 +2726,62 @@
 			   NULL, show_dump_excluded_mappings,
 			   &setlist, &showlist);
 }
+
+/* Fetch (and possibly build) an appropriate `link_map_offsets' for
+   ILP32/LP64 Linux systems which don't have the r_ldsomap field.  */
+
+link_map_offsets *
+linux_ilp32_fetch_link_map_offsets ()
+{
+  static link_map_offsets lmo;
+  static link_map_offsets *lmp = nullptr;
+
+  if (lmp == nullptr)
+    {
+      lmp = &lmo;
+
+      lmo.r_version_offset = 0;
+      lmo.r_version_size = 4;
+      lmo.r_map_offset = 4;
+      lmo.r_brk_offset = 8;
+      lmo.r_ldsomap_offset = -1;
+
+      /* Everything we need is in the first 20 bytes.  */
+      lmo.link_map_size = 20;
+      lmo.l_addr_offset = 0;
+      lmo.l_name_offset = 4;
+      lmo.l_ld_offset = 8;
+      lmo.l_next_offset = 12;
+      lmo.l_prev_offset = 16;
+    }
+
+  return lmp;
+}
+
+link_map_offsets *
+linux_lp64_fetch_link_map_offsets ()
+{
+  static link_map_offsets lmo;
+  static link_map_offsets *lmp = nullptr;
+
+  if (lmp == nullptr)
+    {
+      lmp = &lmo;
+
+      lmo.r_version_offset = 0;
+      lmo.r_version_size = 4;
+      lmo.r_map_offset = 8;
+      lmo.r_brk_offset = 16;
+      lmo.r_ldsomap_offset = -1;
+
+      /* Everything we need is in the first 40 bytes.  */
+      lmo.link_map_size = 40;
+      lmo.l_addr_offset = 0;
+      lmo.l_name_offset = 8;
+      lmo.l_ld_offset = 16;
+      lmo.l_next_offset = 24;
+      lmo.l_prev_offset = 32;
+    }
+
+  return lmp;
+}
diff -Naur gdb-11.2.orig/gdb/linux-tdep.c.orig gdb-11.2/gdb/linux-tdep.c.orig
--- gdb-11.2.orig/gdb/linux-tdep.c.orig	1969-12-31 18:00:00.000000000 -0600
+++ gdb-11.2/gdb/linux-tdep.c.orig	2022-01-16 05:21:18.000000000 -0600
@@ -0,0 +1,2727 @@
+/* Target-dependent code for GNU/Linux, architecture independent.
+
+   Copyright (C) 2009-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 "gdbtypes.h"
+#include "linux-tdep.h"
+#include "auxv.h"
+#include "target.h"
+#include "gdbthread.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "regset.h"
+#include "elf/common.h"
+#include "elf-bfd.h"            /* for elfcore_write_* */
+#include "inferior.h"
+#include "cli/cli-utils.h"
+#include "arch-utils.h"
+#include "gdb_obstack.h"
+#include "observable.h"
+#include "objfiles.h"
+#include "infcall.h"
+#include "gdbcmd.h"
+#include "gdb_regex.h"
+#include "gdbsupport/enum-flags.h"
+#include "gdbsupport/gdb_optional.h"
+#include "gcore.h"
+#include "gcore-elf.h"
+
+#include <ctype.h>
+
+/* This enum represents the values that the user can choose when
+   informing the Linux kernel about which memory mappings will be
+   dumped in a corefile.  They are described in the file
+   Documentation/filesystems/proc.txt, inside the Linux kernel
+   tree.  */
+
+enum filter_flag
+  {
+    COREFILTER_ANON_PRIVATE = 1 << 0,
+    COREFILTER_ANON_SHARED = 1 << 1,
+    COREFILTER_MAPPED_PRIVATE = 1 << 2,
+    COREFILTER_MAPPED_SHARED = 1 << 3,
+    COREFILTER_ELF_HEADERS = 1 << 4,
+    COREFILTER_HUGETLB_PRIVATE = 1 << 5,
+    COREFILTER_HUGETLB_SHARED = 1 << 6,
+  };
+DEF_ENUM_FLAGS_TYPE (enum filter_flag, filter_flags);
+
+/* This struct is used to map flags found in the "VmFlags:" field (in
+   the /proc/<PID>/smaps file).  */
+
+struct smaps_vmflags
+  {
+    /* Zero if this structure has not been initialized yet.  It
+       probably means that the Linux kernel being used does not emit
+       the "VmFlags:" field on "/proc/PID/smaps".  */
+
+    unsigned int initialized_p : 1;
+
+    /* Memory mapped I/O area (VM_IO, "io").  */
+
+    unsigned int io_page : 1;
+
+    /* Area uses huge TLB pages (VM_HUGETLB, "ht").  */
+
+    unsigned int uses_huge_tlb : 1;
+
+    /* Do not include this memory region on the coredump (VM_DONTDUMP, "dd").  */
+
+    unsigned int exclude_coredump : 1;
+
+    /* Is this a MAP_SHARED mapping (VM_SHARED, "sh").  */
+
+    unsigned int shared_mapping : 1;
+
+    /* Memory map has memory tagging enabled.  */
+
+    unsigned int memory_tagging : 1;
+  };
+
+/* Data structure that holds the information contained in the
+   /proc/<pid>/smaps file.  */
+
+struct smaps_data
+{
+  ULONGEST start_address;
+  ULONGEST end_address;
+  std::string filename;
+  struct smaps_vmflags vmflags;
+  bool read;
+  bool write;
+  bool exec;
+  bool priv;
+  bool has_anonymous;
+  bool mapping_anon_p;
+  bool mapping_file_p;
+
+  ULONGEST inode;
+  ULONGEST offset;
+};
+
+/* Whether to take the /proc/PID/coredump_filter into account when
+   generating a corefile.  */
+
+static bool use_coredump_filter = true;
+
+/* Whether the value of smaps_vmflags->exclude_coredump should be
+   ignored, including mappings marked with the VM_DONTDUMP flag in
+   the dump.  */
+static bool dump_excluded_mappings = false;
+
+/* This enum represents the signals' numbers on a generic architecture
+   running the Linux kernel.  The definition of "generic" comes from
+   the file <include/uapi/asm-generic/signal.h>, from the Linux kernel
+   tree, which is the "de facto" implementation of signal numbers to
+   be used by new architecture ports.
+
+   For those architectures which have differences between the generic
+   standard (e.g., Alpha), we define the different signals (and *only*
+   those) in the specific target-dependent file (e.g.,
+   alpha-linux-tdep.c, for Alpha).  Please refer to the architecture's
+   tdep file for more information.
+
+   ARM deserves a special mention here.  On the file
+   <arch/arm/include/uapi/asm/signal.h>, it defines only one different
+   (and ARM-only) signal, which is SIGSWI, with the same number as
+   SIGRTMIN.  This signal is used only for a very specific target,
+   called ArthurOS (from RISCOS).  Therefore, we do not handle it on
+   the ARM-tdep file, and we can safely use the generic signal handler
+   here for ARM targets.
+
+   As stated above, this enum is derived from
+   <include/uapi/asm-generic/signal.h>, from the Linux kernel
+   tree.  */
+
+enum
+  {
+    LINUX_SIGHUP = 1,
+    LINUX_SIGINT = 2,
+    LINUX_SIGQUIT = 3,
+    LINUX_SIGILL = 4,
+    LINUX_SIGTRAP = 5,
+    LINUX_SIGABRT = 6,
+    LINUX_SIGIOT = 6,
+    LINUX_SIGBUS = 7,
+    LINUX_SIGFPE = 8,
+    LINUX_SIGKILL = 9,
+    LINUX_SIGUSR1 = 10,
+    LINUX_SIGSEGV = 11,
+    LINUX_SIGUSR2 = 12,
+    LINUX_SIGPIPE = 13,
+    LINUX_SIGALRM = 14,
+    LINUX_SIGTERM = 15,
+    LINUX_SIGSTKFLT = 16,
+    LINUX_SIGCHLD = 17,
+    LINUX_SIGCONT = 18,
+    LINUX_SIGSTOP = 19,
+    LINUX_SIGTSTP = 20,
+    LINUX_SIGTTIN = 21,
+    LINUX_SIGTTOU = 22,
+    LINUX_SIGURG = 23,
+    LINUX_SIGXCPU = 24,
+    LINUX_SIGXFSZ = 25,
+    LINUX_SIGVTALRM = 26,
+    LINUX_SIGPROF = 27,
+    LINUX_SIGWINCH = 28,
+    LINUX_SIGIO = 29,
+    LINUX_SIGPOLL = LINUX_SIGIO,
+    LINUX_SIGPWR = 30,
+    LINUX_SIGSYS = 31,
+    LINUX_SIGUNUSED = 31,
+
+    LINUX_SIGRTMIN = 32,
+    LINUX_SIGRTMAX = 64,
+  };
+
+static struct gdbarch_data *linux_gdbarch_data_handle;
+
+struct linux_gdbarch_data
+{
+  struct type *siginfo_type;
+  int num_disp_step_buffers;
+};
+
+static void *
+init_linux_gdbarch_data (struct obstack *obstack)
+{
+  return obstack_zalloc<linux_gdbarch_data> (obstack);
+}
+
+static struct linux_gdbarch_data *
+get_linux_gdbarch_data (struct gdbarch *gdbarch)
+{
+  return ((struct linux_gdbarch_data *)
+	  gdbarch_data (gdbarch, linux_gdbarch_data_handle));
+}
+
+/* Linux-specific cached data.  This is used by GDB for caching
+   purposes for each inferior.  This helps reduce the overhead of
+   transfering data from a remote target to the local host.  */
+struct linux_info
+{
+  /* Cache of the inferior's vsyscall/vDSO mapping range.  Only valid
+     if VSYSCALL_RANGE_P is positive.  This is cached because getting
+     at this info requires an auxv lookup (which is itself cached),
+     and looking through the inferior's mappings (which change
+     throughout execution and therefore cannot be cached).  */
+  struct mem_range vsyscall_range {};
+
+  /* Zero if we haven't tried looking up the vsyscall's range before
+     yet.  Positive if we tried looking it up, and found it.  Negative
+     if we tried looking it up but failed.  */
+  int vsyscall_range_p = 0;
+
+  /* Inferior's displaced step buffers.  */
+  gdb::optional<displaced_step_buffers> disp_step_bufs;
+};
+
+/* Per-inferior data key.  */
+static const struct inferior_key<linux_info> linux_inferior_data;
+
+/* Frees whatever allocated space there is to be freed and sets INF's
+   linux cache data pointer to NULL.  */
+
+static void
+invalidate_linux_cache_inf (struct inferior *inf)
+{
+  linux_inferior_data.clear (inf);
+}
+
+/* Fetch the linux cache info for INF.  This function always returns a
+   valid INFO pointer.  */
+
+static struct linux_info *
+get_linux_inferior_data (inferior *inf)
+{
+  linux_info *info = linux_inferior_data.get (inf);
+
+  if (info == nullptr)
+    info = linux_inferior_data.emplace (inf);
+
+  return info;
+}
+
+/* See linux-tdep.h.  */
+
+struct type *
+linux_get_siginfo_type_with_fields (struct gdbarch *gdbarch,
+				    linux_siginfo_extra_fields extra_fields)
+{
+  struct linux_gdbarch_data *linux_gdbarch_data;
+  struct type *int_type, *uint_type, *long_type, *void_ptr_type, *short_type;
+  struct type *uid_type, *pid_type;
+  struct type *sigval_type, *clock_type;
+  struct type *siginfo_type, *sifields_type;
+  struct type *type;
+
+  linux_gdbarch_data = get_linux_gdbarch_data (gdbarch);
+  if (linux_gdbarch_data->siginfo_type != NULL)
+    return linux_gdbarch_data->siginfo_type;
+
+  int_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
+			 	0, "int");
+  uint_type = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch),
+				 1, "unsigned int");
+  long_type = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch),
+				 0, "long");
+  short_type = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch),
+				 0, "short");
+  void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void);
+
+  /* sival_t */
+  sigval_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
+  sigval_type->set_name (xstrdup ("sigval_t"));
+  append_composite_type_field (sigval_type, "sival_int", int_type);
+  append_composite_type_field (sigval_type, "sival_ptr", void_ptr_type);
+
+  /* __pid_t */
+  pid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
+			TYPE_LENGTH (int_type) * TARGET_CHAR_BIT, "__pid_t");
+  TYPE_TARGET_TYPE (pid_type) = int_type;
+  pid_type->set_target_is_stub (true);
+
+  /* __uid_t */
+  uid_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
+			TYPE_LENGTH (uint_type) * TARGET_CHAR_BIT, "__uid_t");
+  TYPE_TARGET_TYPE (uid_type) = uint_type;
+  uid_type->set_target_is_stub (true);
+
+  /* __clock_t */
+  clock_type = arch_type (gdbarch, TYPE_CODE_TYPEDEF,
+			  TYPE_LENGTH (long_type) * TARGET_CHAR_BIT,
+			  "__clock_t");
+  TYPE_TARGET_TYPE (clock_type) = long_type;
+  clock_type->set_target_is_stub (true);
+
+  /* _sifields */
+  sifields_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_UNION);
+
+  {
+    const int si_max_size = 128;
+    int si_pad_size;
+    int size_of_int = gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT;
+
+    /* _pad */
+    if (gdbarch_ptr_bit (gdbarch) == 64)
+      si_pad_size = (si_max_size / size_of_int) - 4;
+    else
+      si_pad_size = (si_max_size / size_of_int) - 3;
+    append_composite_type_field (sifields_type, "_pad",
+				 init_vector_type (int_type, si_pad_size));
+  }
+
+  /* _kill */
+  type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+  append_composite_type_field (type, "si_pid", pid_type);
+  append_composite_type_field (type, "si_uid", uid_type);
+  append_composite_type_field (sifields_type, "_kill", type);
+
+  /* _timer */
+  type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+  append_composite_type_field (type, "si_tid", int_type);
+  append_composite_type_field (type, "si_overrun", int_type);
+  append_composite_type_field (type, "si_sigval", sigval_type);
+  append_composite_type_field (sifields_type, "_timer", type);
+
+  /* _rt */
+  type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+  append_composite_type_field (type, "si_pid", pid_type);
+  append_composite_type_field (type, "si_uid", uid_type);
+  append_composite_type_field (type, "si_sigval", sigval_type);
+  append_composite_type_field (sifields_type, "_rt", type);
+
+  /* _sigchld */
+  type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+  append_composite_type_field (type, "si_pid", pid_type);
+  append_composite_type_field (type, "si_uid", uid_type);
+  append_composite_type_field (type, "si_status", int_type);
+  append_composite_type_field (type, "si_utime", clock_type);
+  append_composite_type_field (type, "si_stime", clock_type);
+  append_composite_type_field (sifields_type, "_sigchld", type);
+
+  /* _sigfault */
+  type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+  append_composite_type_field (type, "si_addr", void_ptr_type);
+
+  /* Additional bound fields for _sigfault in case they were requested.  */
+  if ((extra_fields & LINUX_SIGINFO_FIELD_ADDR_BND) != 0)
+    {
+      struct type *sigfault_bnd_fields;
+
+      append_composite_type_field (type, "_addr_lsb", short_type);
+      sigfault_bnd_fields = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+      append_composite_type_field (sigfault_bnd_fields, "_lower", void_ptr_type);
+      append_composite_type_field (sigfault_bnd_fields, "_upper", void_ptr_type);
+      append_composite_type_field (type, "_addr_bnd", sigfault_bnd_fields);
+    }
+  append_composite_type_field (sifields_type, "_sigfault", type);
+
+  /* _sigpoll */
+  type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+  append_composite_type_field (type, "si_band", long_type);
+  append_composite_type_field (type, "si_fd", int_type);
+  append_composite_type_field (sifields_type, "_sigpoll", type);
+
+  /* struct siginfo */
+  siginfo_type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
+  siginfo_type->set_name (xstrdup ("siginfo"));
+  append_composite_type_field (siginfo_type, "si_signo", int_type);
+  append_composite_type_field (siginfo_type, "si_errno", int_type);
+  append_composite_type_field (siginfo_type, "si_code", int_type);
+  append_composite_type_field_aligned (siginfo_type,
+				       "_sifields", sifields_type,
+				       TYPE_LENGTH (long_type));
+
+  linux_gdbarch_data->siginfo_type = siginfo_type;
+
+  return siginfo_type;
+}
+
+/* This function is suitable for architectures that don't
+   extend/override the standard siginfo structure.  */
+
+static struct type *
+linux_get_siginfo_type (struct gdbarch *gdbarch)
+{
+  return linux_get_siginfo_type_with_fields (gdbarch, 0);
+}
+
+/* Return true if the target is running on uClinux instead of normal
+   Linux kernel.  */
+
+int
+linux_is_uclinux (void)
+{
+  CORE_ADDR dummy;
+  target_ops *target = current_inferior ()->top_target ();
+
+  return (target_auxv_search (target, AT_NULL, &dummy) > 0
+	  && target_auxv_search (target, AT_PAGESZ, &dummy) == 0);
+}
+
+static int
+linux_has_shared_address_space (struct gdbarch *gdbarch)
+{
+  return linux_is_uclinux ();
+}
+
+/* This is how we want PTIDs from core files to be printed.  */
+
+static std::string
+linux_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid)
+{
+  if (ptid.lwp () != 0)
+    return string_printf ("LWP %ld", ptid.lwp ());
+
+  return normal_pid_to_str (ptid);
+}
+
+/* Service function for corefiles and info proc.  */
+
+static void
+read_mapping (const char *line,
+	      ULONGEST *addr, ULONGEST *endaddr,
+	      const char **permissions, size_t *permissions_len,
+	      ULONGEST *offset,
+	      const char **device, size_t *device_len,
+	      ULONGEST *inode,
+	      const char **filename)
+{
+  const char *p = line;
+
+  *addr = strtoulst (p, &p, 16);
+  if (*p == '-')
+    p++;
+  *endaddr = strtoulst (p, &p, 16);
+
+  p = skip_spaces (p);
+  *permissions = p;
+  while (*p && !isspace (*p))
+    p++;
+  *permissions_len = p - *permissions;
+
+  *offset = strtoulst (p, &p, 16);
+
+  p = skip_spaces (p);
+  *device = p;
+  while (*p && !isspace (*p))
+    p++;
+  *device_len = p - *device;
+
+  *inode = strtoulst (p, &p, 10);
+
+  p = skip_spaces (p);
+  *filename = p;
+}
+
+/* Helper function to decode the "VmFlags" field in /proc/PID/smaps.
+
+   This function was based on the documentation found on
+   <Documentation/filesystems/proc.txt>, on the Linux kernel.
+
+   Linux kernels before commit
+   834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have this
+   field on smaps.  */
+
+static void
+decode_vmflags (char *p, struct smaps_vmflags *v)
+{
+  char *saveptr = NULL;
+  const char *s;
+
+  v->initialized_p = 1;
+  p = skip_to_space (p);
+  p = skip_spaces (p);
+
+  for (s = strtok_r (p, " ", &saveptr);
+       s != NULL;
+       s = strtok_r (NULL, " ", &saveptr))
+    {
+      if (strcmp (s, "io") == 0)
+	v->io_page = 1;
+      else if (strcmp (s, "ht") == 0)
+	v->uses_huge_tlb = 1;
+      else if (strcmp (s, "dd") == 0)
+	v->exclude_coredump = 1;
+      else if (strcmp (s, "sh") == 0)
+	v->shared_mapping = 1;
+      else if (strcmp (s, "mt") == 0)
+	v->memory_tagging = 1;
+    }
+}
+
+/* Regexes used by mapping_is_anonymous_p.  Put in a structure because
+   they're initialized lazily.  */
+
+struct mapping_regexes
+{
+  /* Matches "/dev/zero" filenames (with or without the "(deleted)"
+     string in the end).  We know for sure, based on the Linux kernel
+     code, that memory mappings whose associated filename is
+     "/dev/zero" are guaranteed to be MAP_ANONYMOUS.  */
+  compiled_regex dev_zero
+    {"^/dev/zero\\( (deleted)\\)\\?$", REG_NOSUB,
+     _("Could not compile regex to match /dev/zero filename")};
+
+  /* Matches "/SYSV%08x" filenames (with or without the "(deleted)"
+     string in the end).  These filenames refer to shared memory
+     (shmem), and memory mappings associated with them are
+     MAP_ANONYMOUS as well.  */
+  compiled_regex shmem_file
+    {"^/\\?SYSV[0-9a-fA-F]\\{8\\}\\( (deleted)\\)\\?$", REG_NOSUB,
+     _("Could not compile regex to match shmem filenames")};
+
+  /* A heuristic we use to try to mimic the Linux kernel's 'n_link ==
+     0' code, which is responsible to decide if it is dealing with a
+     'MAP_SHARED | MAP_ANONYMOUS' mapping.  In other words, if
+     FILE_DELETED matches, it does not necessarily mean that we are
+     dealing with an anonymous shared mapping.  However, there is no
+     easy way to detect this currently, so this is the best
+     approximation we have.
+
+     As a result, GDB will dump readonly pages of deleted executables
+     when using the default value of coredump_filter (0x33), while the
+     Linux kernel will not dump those pages.  But we can live with
+     that.  */
+  compiled_regex file_deleted
+    {" (deleted)$", REG_NOSUB,
+     _("Could not compile regex to match '<file> (deleted)'")};
+};
+
+/* Return 1 if the memory mapping is anonymous, 0 otherwise.
+
+   FILENAME is the name of the file present in the first line of the
+   memory mapping, in the "/proc/PID/smaps" output.  For example, if
+   the first line is:
+
+   7fd0ca877000-7fd0d0da0000 r--p 00000000 fd:02 2100770   /path/to/file
+
+   Then FILENAME will be "/path/to/file".  */
+
+static int
+mapping_is_anonymous_p (const char *filename)
+{
+  static gdb::optional<mapping_regexes> regexes;
+  static int init_regex_p = 0;
+
+  if (!init_regex_p)
+    {
+      /* Let's be pessimistic and assume there will be an error while
+	 compiling the regex'es.  */
+      init_regex_p = -1;
+
+      regexes.emplace ();
+
+      /* If we reached this point, then everything succeeded.  */
+      init_regex_p = 1;
+    }
+
+  if (init_regex_p == -1)
+    {
+      const char deleted[] = " (deleted)";
+      size_t del_len = sizeof (deleted) - 1;
+      size_t filename_len = strlen (filename);
+
+      /* There was an error while compiling the regex'es above.  In
+	 order to try to give some reliable information to the caller,
+	 we just try to find the string " (deleted)" in the filename.
+	 If we managed to find it, then we assume the mapping is
+	 anonymous.  */
+      return (filename_len >= del_len
+	      && strcmp (filename + filename_len - del_len, deleted) == 0);
+    }
+
+  if (*filename == '\0'
+      || regexes->dev_zero.exec (filename, 0, NULL, 0) == 0
+      || regexes->shmem_file.exec (filename, 0, NULL, 0) == 0
+      || regexes->file_deleted.exec (filename, 0, NULL, 0) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* Return 0 if the memory mapping (which is related to FILTERFLAGS, V,
+   MAYBE_PRIVATE_P, MAPPING_ANONYMOUS_P, ADDR and OFFSET) should not
+   be dumped, or greater than 0 if it should.
+
+   In a nutshell, this is the logic that we follow in order to decide
+   if a mapping should be dumped or not.
+
+   - If the mapping is associated to a file whose name ends with
+     " (deleted)", or if the file is "/dev/zero", or if it is
+     "/SYSV%08x" (shared memory), or if there is no file associated
+     with it, or if the AnonHugePages: or the Anonymous: fields in the
+     /proc/PID/smaps have contents, then GDB considers this mapping to
+     be anonymous.  Otherwise, GDB considers this mapping to be a
+     file-backed mapping (because there will be a file associated with
+     it).
+ 
+     It is worth mentioning that, from all those checks described
+     above, the most fragile is the one to see if the file name ends
+     with " (deleted)".  This does not necessarily mean that the
+     mapping is anonymous, because the deleted file associated with
+     the mapping may have been a hard link to another file, for
+     example.  The Linux kernel checks to see if "i_nlink == 0", but
+     GDB cannot easily (and normally) do this check (iff running as
+     root, it could find the mapping in /proc/PID/map_files/ and
+     determine whether there still are other hard links to the
+     inode/file).  Therefore, we made a compromise here, and we assume
+     that if the file name ends with " (deleted)", then the mapping is
+     indeed anonymous.  FWIW, this is something the Linux kernel could
+     do better: expose this information in a more direct way.
+ 
+   - If we see the flag "sh" in the "VmFlags:" field (in
+     /proc/PID/smaps), then certainly the memory mapping is shared
+     (VM_SHARED).  If we have access to the VmFlags, and we don't see
+     the "sh" there, then certainly the mapping is private.  However,
+     Linux kernels before commit
+     834f82e2aa9a8ede94b17b656329f850c1471514 (3.10) do not have the
+     "VmFlags:" field; in that case, we use another heuristic: if we
+     see 'p' in the permission flags, then we assume that the mapping
+     is private, even though the presence of the 's' flag there would
+     mean VM_MAYSHARE, which means the mapping could still be private.
+     This should work OK enough, however.
+
+   - Even if, at the end, we decided that we should not dump the
+     mapping, we still have to check if it is something like an ELF
+     header (of a DSO or an executable, for example).  If it is, and
+     if the user is interested in dump it, then we should dump it.  */
+
+static int
+dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
+		int maybe_private_p, int mapping_anon_p, int mapping_file_p,
+		const char *filename, ULONGEST addr, ULONGEST offset)
+{
+  /* Initially, we trust in what we received from our caller.  This
+     value may not be very precise (i.e., it was probably gathered
+     from the permission line in the /proc/PID/smaps list, which
+     actually refers to VM_MAYSHARE, and not VM_SHARED), but it is
+     what we have until we take a look at the "VmFlags:" field
+     (assuming that the version of the Linux kernel being used
+     supports it, of course).  */
+  int private_p = maybe_private_p;
+  int dump_p;
+
+  /* We always dump vDSO and vsyscall mappings, because it's likely that
+     there'll be no file to read the contents from at core load time.
+     The kernel does the same.  */
+  if (strcmp ("[vdso]", filename) == 0
+      || strcmp ("[vsyscall]", filename) == 0)
+    return 1;
+
+  if (v->initialized_p)
+    {
+      /* We never dump I/O mappings.  */
+      if (v->io_page)
+	return 0;
+
+      /* Check if we should exclude this mapping.  */
+      if (!dump_excluded_mappings && v->exclude_coredump)
+	return 0;
+
+      /* Update our notion of whether this mapping is shared or
+	 private based on a trustworthy value.  */
+      private_p = !v->shared_mapping;
+
+      /* HugeTLB checking.  */
+      if (v->uses_huge_tlb)
+	{
+	  if ((private_p && (filterflags & COREFILTER_HUGETLB_PRIVATE))
+	      || (!private_p && (filterflags & COREFILTER_HUGETLB_SHARED)))
+	    return 1;
+
+	  return 0;
+	}
+    }
+
+  if (private_p)
+    {
+      if (mapping_anon_p && mapping_file_p)
+	{
+	  /* This is a special situation.  It can happen when we see a
+	     mapping that is file-backed, but that contains anonymous
+	     pages.  */
+	  dump_p = ((filterflags & COREFILTER_ANON_PRIVATE) != 0
+		    || (filterflags & COREFILTER_MAPPED_PRIVATE) != 0);
+	}
+      else if (mapping_anon_p)
+	dump_p = (filterflags & COREFILTER_ANON_PRIVATE) != 0;
+      else
+	dump_p = (filterflags & COREFILTER_MAPPED_PRIVATE) != 0;
+    }
+  else
+    {
+      if (mapping_anon_p && mapping_file_p)
+	{
+	  /* This is a special situation.  It can happen when we see a
+	     mapping that is file-backed, but that contains anonymous
+	     pages.  */
+	  dump_p = ((filterflags & COREFILTER_ANON_SHARED) != 0
+		    || (filterflags & COREFILTER_MAPPED_SHARED) != 0);
+	}
+      else if (mapping_anon_p)
+	dump_p = (filterflags & COREFILTER_ANON_SHARED) != 0;
+      else
+	dump_p = (filterflags & COREFILTER_MAPPED_SHARED) != 0;
+    }
+
+  /* Even if we decided that we shouldn't dump this mapping, we still
+     have to check whether (a) the user wants us to dump mappings
+     containing an ELF header, and (b) the mapping in question
+     contains an ELF header.  If (a) and (b) are true, then we should
+     dump this mapping.
+
+     A mapping contains an ELF header if it is a private mapping, its
+     offset is zero, and its first word is ELFMAG.  */
+  if (!dump_p && private_p && offset == 0
+      && (filterflags & COREFILTER_ELF_HEADERS) != 0)
+    {
+      /* Useful define specifying the size of the ELF magical
+	 header.  */
+#ifndef SELFMAG
+#define SELFMAG 4
+#endif
+
+      /* Let's check if we have an ELF header.  */
+      gdb_byte h[SELFMAG];
+      if (target_read_memory (addr, h, SELFMAG) == 0)
+	{
+	  /* The EI_MAG* and ELFMAG* constants come from
+	     <elf/common.h>.  */
+	  if (h[EI_MAG0] == ELFMAG0 && h[EI_MAG1] == ELFMAG1
+	      && h[EI_MAG2] == ELFMAG2 && h[EI_MAG3] == ELFMAG3)
+	    {
+	      /* This mapping contains an ELF header, so we
+		 should dump it.  */
+	      dump_p = 1;
+	    }
+	}
+    }
+
+  return dump_p;
+}
+
+/* As above, but return true only when we should dump the NT_FILE
+   entry.  */
+
+static int
+dump_note_entry_p (filter_flags filterflags, const struct smaps_vmflags *v,
+		int maybe_private_p, int mapping_anon_p, int mapping_file_p,
+		const char *filename, ULONGEST addr, ULONGEST offset)
+{
+  /* vDSO and vsyscall mappings will end up in the core file.  Don't
+     put them in the NT_FILE note.  */
+  if (strcmp ("[vdso]", filename) == 0
+      || strcmp ("[vsyscall]", filename) == 0)
+    return 0;
+
+  /* Otherwise, any other file-based mapping should be placed in the
+     note.  */
+  return 1;
+}
+
+/* Implement the "info proc" command.  */
+
+static void
+linux_info_proc (struct gdbarch *gdbarch, const char *args,
+		 enum info_proc_what what)
+{
+  /* A long is used for pid instead of an int to avoid a loss of precision
+     compiler warning from the output of strtoul.  */
+  long pid;
+  int cmdline_f = (what == IP_MINIMAL || what == IP_CMDLINE || what == IP_ALL);
+  int cwd_f = (what == IP_MINIMAL || what == IP_CWD || what == IP_ALL);
+  int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
+  int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
+  int status_f = (what == IP_STATUS || what == IP_ALL);
+  int stat_f = (what == IP_STAT || what == IP_ALL);
+  char filename[100];
+  int target_errno;
+
+  if (args && isdigit (args[0]))
+    {
+      char *tem;
+
+      pid = strtoul (args, &tem, 10);
+      args = tem;
+    }
+  else
+    {
+      if (!target_has_execution ())
+	error (_("No current process: you must name one."));
+      if (current_inferior ()->fake_pid_p)
+	error (_("Can't determine the current process's PID: you must name one."));
+
+      pid = current_inferior ()->pid;
+    }
+
+  args = skip_spaces (args);
+  if (args && args[0])
+    error (_("Too many parameters: %s"), args);
+
+  printf_filtered (_("process %ld\n"), pid);
+  if (cmdline_f)
+    {
+      xsnprintf (filename, sizeof filename, "/proc/%ld/cmdline", pid);
+      gdb_byte *buffer;
+      ssize_t len = target_fileio_read_alloc (NULL, filename, &buffer);
+
+      if (len > 0)
+	{
+	  gdb::unique_xmalloc_ptr<char> cmdline ((char *) buffer);
+	  ssize_t pos;
+
+	  for (pos = 0; pos < len - 1; pos++)
+	    {
+	      if (buffer[pos] == '\0')
+		buffer[pos] = ' ';
+	    }
+	  buffer[len - 1] = '\0';
+	  printf_filtered ("cmdline = '%s'\n", buffer);
+	}
+      else
+	warning (_("unable to open /proc file '%s'"), filename);
+    }
+  if (cwd_f)
+    {
+      xsnprintf (filename, sizeof filename, "/proc/%ld/cwd", pid);
+      gdb::optional<std::string> contents
+	= target_fileio_readlink (NULL, filename, &target_errno);
+      if (contents.has_value ())
+	printf_filtered ("cwd = '%s'\n", contents->c_str ());
+      else
+	warning (_("unable to read link '%s'"), filename);
+    }
+  if (exe_f)
+    {
+      xsnprintf (filename, sizeof filename, "/proc/%ld/exe", pid);
+      gdb::optional<std::string> contents
+	= target_fileio_readlink (NULL, filename, &target_errno);
+      if (contents.has_value ())
+	printf_filtered ("exe = '%s'\n", contents->c_str ());
+      else
+	warning (_("unable to read link '%s'"), filename);
+    }
+  if (mappings_f)
+    {
+      xsnprintf (filename, sizeof filename, "/proc/%ld/maps", pid);
+      gdb::unique_xmalloc_ptr<char> map
+	= target_fileio_read_stralloc (NULL, filename);
+      if (map != NULL)
+	{
+	  char *line;
+
+	  printf_filtered (_("Mapped address spaces:\n\n"));
+	  if (gdbarch_addr_bit (gdbarch) == 32)
+	    {
+	      printf_filtered ("\t%10s %10s %10s %10s %s\n",
+			   "Start Addr",
+			   "  End Addr",
+			   "      Size", "    Offset", "objfile");
+	    }
+	  else
+	    {
+	      printf_filtered ("  %18s %18s %10s %10s %s\n",
+			   "Start Addr",
+			   "  End Addr",
+			   "      Size", "    Offset", "objfile");
+	    }
+
+	  char *saveptr;
+	  for (line = strtok_r (map.get (), "\n", &saveptr);
+	       line;
+	       line = strtok_r (NULL, "\n", &saveptr))
+	    {
+	      ULONGEST addr, endaddr, offset, inode;
+	      const char *permissions, *device, *mapping_filename;
+	      size_t permissions_len, device_len;
+
+	      read_mapping (line, &addr, &endaddr,
+			    &permissions, &permissions_len,
+			    &offset, &device, &device_len,
+			    &inode, &mapping_filename);
+
+	      if (gdbarch_addr_bit (gdbarch) == 32)
+		{
+		  printf_filtered ("\t%10s %10s %10s %10s %s\n",
+				   paddress (gdbarch, addr),
+				   paddress (gdbarch, endaddr),
+				   hex_string (endaddr - addr),
+				   hex_string (offset),
+				   *mapping_filename ? mapping_filename : "");
+		}
+	      else
+		{
+		  printf_filtered ("  %18s %18s %10s %10s %s\n",
+				   paddress (gdbarch, addr),
+				   paddress (gdbarch, endaddr),
+				   hex_string (endaddr - addr),
+				   hex_string (offset),
+				   *mapping_filename ? mapping_filename : "");
+		}
+	    }
+	}
+      else
+	warning (_("unable to open /proc file '%s'"), filename);
+    }
+  if (status_f)
+    {
+      xsnprintf (filename, sizeof filename, "/proc/%ld/status", pid);
+      gdb::unique_xmalloc_ptr<char> status
+	= target_fileio_read_stralloc (NULL, filename);
+      if (status)
+	puts_filtered (status.get ());
+      else
+	warning (_("unable to open /proc file '%s'"), filename);
+    }
+  if (stat_f)
+    {
+      xsnprintf (filename, sizeof filename, "/proc/%ld/stat", pid);
+      gdb::unique_xmalloc_ptr<char> statstr
+	= target_fileio_read_stralloc (NULL, filename);
+      if (statstr)
+	{
+	  const char *p = statstr.get ();
+
+	  printf_filtered (_("Process: %s\n"),
+			   pulongest (strtoulst (p, &p, 10)));
+
+	  p = skip_spaces (p);
+	  if (*p == '(')
+	    {
+	      /* ps command also relies on no trailing fields
+		 ever contain ')'.  */
+	      const char *ep = strrchr (p, ')');
+	      if (ep != NULL)
+		{
+		  printf_filtered ("Exec file: %.*s\n",
+				   (int) (ep - p - 1), p + 1);
+		  p = ep + 1;
+		}
+	    }
+
+	  p = skip_spaces (p);
+	  if (*p)
+	    printf_filtered (_("State: %c\n"), *p++);
+
+	  if (*p)
+	    printf_filtered (_("Parent process: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Process group: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Session id: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("TTY: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("TTY owner process group: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+
+	  if (*p)
+	    printf_filtered (_("Flags: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Minor faults (no memory page): %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Minor faults, children: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Major faults (memory page faults): %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Major faults, children: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("utime: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("stime: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("utime, children: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("stime, children: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("jiffies remaining in current "
+			       "time slice: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("'nice' value: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("jiffies until next timeout: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("jiffies until next SIGALRM: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("start time (jiffies since "
+			       "system boot): %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Virtual memory size: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Resident set size: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("rlim: %s\n"),
+			     pulongest (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Start of text: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("End of text: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Start of stack: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+#if 0	/* Don't know how architecture-dependent the rest is...
+	   Anyway the signal bitmap info is available from "status".  */
+	  if (*p)
+	    printf_filtered (_("Kernel stack pointer: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Kernel instr pointer: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Pending signals bitmap: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Blocked signals bitmap: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Ignored signals bitmap: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("Catched signals bitmap: %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+	  if (*p)
+	    printf_filtered (_("wchan (system call): %s\n"),
+			     hex_string (strtoulst (p, &p, 10)));
+#endif
+	}
+      else
+	warning (_("unable to open /proc file '%s'"), filename);
+    }
+}
+
+/* Implementation of `gdbarch_read_core_file_mappings', as defined in
+   gdbarch.h.
+   
+   This function reads the NT_FILE note (which BFD turns into the
+   section ".note.linuxcore.file").  The format of this note / section
+   is described as follows in the Linux kernel sources in
+   fs/binfmt_elf.c:
+   
+      long count     -- how many files are mapped
+      long page_size -- units for file_ofs
+      array of [COUNT] elements of
+	long start
+	long end
+	long file_ofs
+      followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
+      
+   CBFD is the BFD of the core file.
+
+   PRE_LOOP_CB is the callback function to invoke prior to starting
+   the loop which processes individual entries.  This callback will
+   only be executed after the note has been examined in enough
+   detail to verify that it's not malformed in some way.
+   
+   LOOP_CB is the callback function that will be executed once
+   for each mapping.  */
+
+static void
+linux_read_core_file_mappings (struct gdbarch *gdbarch,
+			       struct bfd *cbfd,
+			       gdb::function_view<void (ULONGEST count)>
+				 pre_loop_cb,
+			       gdb::function_view<void (int num,
+							ULONGEST start,
+							ULONGEST end,
+							ULONGEST file_ofs,
+							const char *filename)>
+				 loop_cb)
+{
+  /* Ensure that ULONGEST is big enough for reading 64-bit core files.  */
+  gdb_static_assert (sizeof (ULONGEST) >= 8);
+
+  /* It's not required that the NT_FILE note exists, so return silently
+     if it's not found.  Beyond this point though, we'll complain
+     if problems are found.  */
+  asection *section = bfd_get_section_by_name (cbfd, ".note.linuxcore.file");
+  if (section == nullptr)
+    return;
+
+  unsigned int addr_size_bits = gdbarch_addr_bit (gdbarch);
+  unsigned int addr_size = addr_size_bits / 8;
+  size_t note_size = bfd_section_size (section);
+
+  if (note_size < 2 * addr_size)
+    {
+      warning (_("malformed core note - too short for header"));
+      return;
+    }
+
+  gdb::def_vector<gdb_byte> contents (note_size);
+  if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+				 0, note_size))
+    {
+      warning (_("could not get core note contents"));
+      return;
+    }
+
+  gdb_byte *descdata = contents.data ();
+  char *descend = (char *) descdata + note_size;
+
+  if (descdata[note_size - 1] != '\0')
+    {
+      warning (_("malformed note - does not end with \\0"));
+      return;
+    }
+
+  ULONGEST count = bfd_get (addr_size_bits, core_bfd, descdata);
+  descdata += addr_size;
+
+  ULONGEST page_size = bfd_get (addr_size_bits, core_bfd, descdata);
+  descdata += addr_size;
+
+  if (note_size < 2 * addr_size + count * 3 * addr_size)
+    {
+      warning (_("malformed note - too short for supplied file count"));
+      return;
+    }
+
+  char *filenames = (char *) descdata + count * 3 * addr_size;
+
+  /* Make sure that the correct number of filenames exist.  Complain
+     if there aren't enough or are too many.  */
+  char *f = filenames;
+  for (int i = 0; i < count; i++)
+    {
+      if (f >= descend)
+	{
+	  warning (_("malformed note - filename area is too small"));
+	  return;
+	}
+      f += strnlen (f, descend - f) + 1;
+    }
+  /* Complain, but don't return early if the filename area is too big.  */
+  if (f != descend)
+    warning (_("malformed note - filename area is too big"));
+
+  pre_loop_cb (count);
+
+  for (int i = 0; i < count; i++)
+    {
+      ULONGEST start = bfd_get (addr_size_bits, core_bfd, descdata);
+      descdata += addr_size;
+      ULONGEST end = bfd_get (addr_size_bits, core_bfd, descdata);
+      descdata += addr_size;
+      ULONGEST file_ofs
+	= bfd_get (addr_size_bits, core_bfd, descdata) * page_size;
+      descdata += addr_size;
+      char * filename = filenames;
+      filenames += strlen ((char *) filenames) + 1;
+
+      loop_cb (i, start, end, file_ofs, filename);
+    }
+}
+
+/* Implement "info proc mappings" for a corefile.  */
+
+static void
+linux_core_info_proc_mappings (struct gdbarch *gdbarch, const char *args)
+{
+  linux_read_core_file_mappings (gdbarch, core_bfd,
+    [=] (ULONGEST count)
+      {
+	printf_filtered (_("Mapped address spaces:\n\n"));
+	if (gdbarch_addr_bit (gdbarch) == 32)
+	  {
+	    printf_filtered ("\t%10s %10s %10s %10s %s\n",
+			     "Start Addr",
+			     "  End Addr",
+			     "      Size", "    Offset", "objfile");
+	  }
+	else
+	  {
+	    printf_filtered ("  %18s %18s %10s %10s %s\n",
+			     "Start Addr",
+			     "  End Addr",
+			     "      Size", "    Offset", "objfile");
+	  }
+      },
+    [=] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
+	 const char *filename)
+      {
+	if (gdbarch_addr_bit (gdbarch) == 32)
+	  printf_filtered ("\t%10s %10s %10s %10s %s\n",
+			   paddress (gdbarch, start),
+			   paddress (gdbarch, end),
+			   hex_string (end - start),
+			   hex_string (file_ofs),
+			   filename);
+	else
+	  printf_filtered ("  %18s %18s %10s %10s %s\n",
+			   paddress (gdbarch, start),
+			   paddress (gdbarch, end),
+			   hex_string (end - start),
+			   hex_string (file_ofs),
+			   filename);
+      });
+}
+
+/* Implement "info proc" for a corefile.  */
+
+static void
+linux_core_info_proc (struct gdbarch *gdbarch, const char *args,
+		      enum info_proc_what what)
+{
+  int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
+  int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
+
+  if (exe_f)
+    {
+      const char *exe;
+
+      exe = bfd_core_file_failing_command (core_bfd);
+      if (exe != NULL)
+	printf_filtered ("exe = '%s'\n", exe);
+      else
+	warning (_("unable to find command name in core file"));
+    }
+
+  if (mappings_f)
+    linux_core_info_proc_mappings (gdbarch, args);
+
+  if (!exe_f && !mappings_f)
+    error (_("unable to handle request"));
+}
+
+/* Read siginfo data from the core, if possible.  Returns -1 on
+   failure.  Otherwise, returns the number of bytes read.  READBUF,
+   OFFSET, and LEN are all as specified by the to_xfer_partial
+   interface.  */
+
+static LONGEST
+linux_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf,
+			 ULONGEST offset, ULONGEST len)
+{
+  thread_section_name section_name (".note.linuxcore.siginfo", inferior_ptid);
+  asection *section = bfd_get_section_by_name (core_bfd, section_name.c_str ());
+  if (section == NULL)
+    return -1;
+
+  if (!bfd_get_section_contents (core_bfd, section, readbuf, offset, len))
+    return -1;
+
+  return len;
+}
+
+typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
+					    ULONGEST offset, ULONGEST inode,
+					    int read, int write,
+					    int exec, int modified,
+					    const char *filename,
+					    void *data);
+
+typedef int linux_dump_mapping_p_ftype (filter_flags filterflags,
+					const struct smaps_vmflags *v,
+					int maybe_private_p,
+					int mapping_anon_p,
+					int mapping_file_p,
+					const char *filename,
+					ULONGEST addr,
+					ULONGEST offset);
+
+/* Helper function to parse the contents of /proc/<pid>/smaps into a data
+   structure, for easy access.
+
+   DATA is the contents of the smaps file.  The parsed contents are stored
+   into the SMAPS vector.  */
+
+static std::vector<struct smaps_data>
+parse_smaps_data (const char *data,
+		  const std::string maps_filename)
+{
+  char *line, *t;
+
+  gdb_assert (data != nullptr);
+
+  line = strtok_r ((char *) data, "\n", &t);
+
+  std::vector<struct smaps_data> smaps;
+
+  while (line != NULL)
+    {
+      ULONGEST addr, endaddr, offset, inode;
+      const char *permissions, *device, *filename;
+      struct smaps_vmflags v;
+      size_t permissions_len, device_len;
+      int read, write, exec, priv;
+      int has_anonymous = 0;
+      int mapping_anon_p;
+      int mapping_file_p;
+
+      memset (&v, 0, sizeof (v));
+      read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
+		    &offset, &device, &device_len, &inode, &filename);
+      mapping_anon_p = mapping_is_anonymous_p (filename);
+      /* If the mapping is not anonymous, then we can consider it
+	 to be file-backed.  These two states (anonymous or
+	 file-backed) seem to be exclusive, but they can actually
+	 coexist.  For example, if a file-backed mapping has
+	 "Anonymous:" pages (see more below), then the Linux
+	 kernel will dump this mapping when the user specified
+	 that she only wants anonymous mappings in the corefile
+	 (*even* when she explicitly disabled the dumping of
+	 file-backed mappings).  */
+      mapping_file_p = !mapping_anon_p;
+
+      /* Decode permissions.  */
+      read = (memchr (permissions, 'r', permissions_len) != 0);
+      write = (memchr (permissions, 'w', permissions_len) != 0);
+      exec = (memchr (permissions, 'x', permissions_len) != 0);
+      /* 'private' here actually means VM_MAYSHARE, and not
+	 VM_SHARED.  In order to know if a mapping is really
+	 private or not, we must check the flag "sh" in the
+	 VmFlags field.  This is done by decode_vmflags.  However,
+	 if we are using a Linux kernel released before the commit
+	 834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
+	 not have the VmFlags there.  In this case, there is
+	 really no way to know if we are dealing with VM_SHARED,
+	 so we just assume that VM_MAYSHARE is enough.  */
+      priv = memchr (permissions, 'p', permissions_len) != 0;
+
+      /* Try to detect if region should be dumped by parsing smaps
+	 counters.  */
+      for (line = strtok_r (NULL, "\n", &t);
+	   line != NULL && line[0] >= 'A' && line[0] <= 'Z';
+	   line = strtok_r (NULL, "\n", &t))
+	{
+	  char keyword[64 + 1];
+
+	  if (sscanf (line, "%64s", keyword) != 1)
+	    {
+	      warning (_("Error parsing {s,}maps file '%s'"),
+		       maps_filename.c_str ());
+	      break;
+	    }
+
+	  if (strcmp (keyword, "Anonymous:") == 0)
+	    {
+	      /* Older Linux kernels did not support the
+		 "Anonymous:" counter.  Check it here.  */
+	      has_anonymous = 1;
+	    }
+	  else if (strcmp (keyword, "VmFlags:") == 0)
+	    decode_vmflags (line, &v);
+
+	  if (strcmp (keyword, "AnonHugePages:") == 0
+	      || strcmp (keyword, "Anonymous:") == 0)
+	    {
+	      unsigned long number;
+
+	      if (sscanf (line, "%*s%lu", &number) != 1)
+		{
+		  warning (_("Error parsing {s,}maps file '%s' number"),
+			   maps_filename.c_str ());
+		  break;
+		}
+	      if (number > 0)
+		{
+		  /* Even if we are dealing with a file-backed
+		     mapping, if it contains anonymous pages we
+		     consider it to be *also* an anonymous
+		     mapping, because this is what the Linux
+		     kernel does:
+
+		     // Dump segments that have been written to.
+		     if (vma->anon_vma && FILTER(ANON_PRIVATE))
+		       goto whole;
+
+		    Note that if the mapping is already marked as
+		    file-backed (i.e., mapping_file_p is
+		    non-zero), then this is a special case, and
+		    this mapping will be dumped either when the
+		    user wants to dump file-backed *or* anonymous
+		    mappings.  */
+		  mapping_anon_p = 1;
+		}
+	    }
+	}
+      /* Save the smaps entry to the vector.  */
+	struct smaps_data map;
+
+	map.start_address = addr;
+	map.end_address = endaddr;
+	map.filename = filename;
+	map.vmflags = v;
+	map.read = read? true : false;
+	map.write = write? true : false;
+	map.exec = exec? true : false;
+	map.priv = priv? true : false;
+	map.has_anonymous = has_anonymous;
+	map.mapping_anon_p = mapping_anon_p? true : false;
+	map.mapping_file_p = mapping_file_p? true : false;
+	map.offset = offset;
+	map.inode = inode;
+
+	smaps.emplace_back (map);
+    }
+
+  return smaps;
+}
+
+/* See linux-tdep.h.  */
+
+bool
+linux_address_in_memtag_page (CORE_ADDR address)
+{
+  if (current_inferior ()->fake_pid_p)
+    return false;
+
+  pid_t pid = current_inferior ()->pid;
+
+  std::string smaps_file = string_printf ("/proc/%d/smaps", pid);
+
+  gdb::unique_xmalloc_ptr<char> data
+    = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
+
+  if (data == nullptr)
+    return false;
+
+  /* Parse the contents of smaps into a vector.  */
+  std::vector<struct smaps_data> smaps
+    = parse_smaps_data (data.get (), smaps_file);
+
+  for (const smaps_data &map : smaps)
+    {
+      /* Is the address within [start_address, end_address) in a page
+	 mapped with memory tagging?  */
+      if (address >= map.start_address
+	  && address < map.end_address
+	  && map.vmflags.memory_tagging)
+	return true;
+    }
+
+  return false;
+}
+
+/* List memory regions in the inferior for a corefile.  */
+
+static int
+linux_find_memory_regions_full (struct gdbarch *gdbarch,
+				linux_dump_mapping_p_ftype *should_dump_mapping_p,
+				linux_find_memory_region_ftype *func,
+				void *obfd)
+{
+  pid_t pid;
+  /* Default dump behavior of coredump_filter (0x33), according to
+     Documentation/filesystems/proc.txt from the Linux kernel
+     tree.  */
+  filter_flags filterflags = (COREFILTER_ANON_PRIVATE
+			      | COREFILTER_ANON_SHARED
+			      | COREFILTER_ELF_HEADERS
+			      | COREFILTER_HUGETLB_PRIVATE);
+
+  /* We need to know the real target PID to access /proc.  */
+  if (current_inferior ()->fake_pid_p)
+    return 1;
+
+  pid = current_inferior ()->pid;
+
+  if (use_coredump_filter)
+    {
+      std::string core_dump_filter_name
+	= string_printf ("/proc/%d/coredump_filter", pid);
+
+      gdb::unique_xmalloc_ptr<char> coredumpfilterdata
+	= target_fileio_read_stralloc (NULL, core_dump_filter_name.c_str ());
+
+      if (coredumpfilterdata != NULL)
+	{
+	  unsigned int flags;
+
+	  sscanf (coredumpfilterdata.get (), "%x", &flags);
+	  filterflags = (enum filter_flag) flags;
+	}
+    }
+
+  std::string maps_filename = string_printf ("/proc/%d/smaps", pid);
+
+  gdb::unique_xmalloc_ptr<char> data
+    = target_fileio_read_stralloc (NULL, maps_filename.c_str ());
+
+  if (data == NULL)
+    {
+      /* Older Linux kernels did not support /proc/PID/smaps.  */
+      maps_filename = string_printf ("/proc/%d/maps", pid);
+      data = target_fileio_read_stralloc (NULL, maps_filename.c_str ());
+
+      if (data == nullptr)
+	return 1;
+    }
+
+  /* Parse the contents of smaps into a vector.  */
+  std::vector<struct smaps_data> smaps
+    = parse_smaps_data (data.get (), maps_filename.c_str ());
+
+  for (const struct smaps_data &map : smaps)
+    {
+      int should_dump_p = 0;
+
+      if (map.has_anonymous)
+	{
+	  should_dump_p
+	    = should_dump_mapping_p (filterflags, &map.vmflags,
+				     map.priv,
+				     map.mapping_anon_p,
+				     map.mapping_file_p,
+				     map.filename.c_str (),
+				     map.start_address,
+				     map.offset);
+	}
+      else
+	{
+	  /* Older Linux kernels did not support the "Anonymous:" counter.
+	     If it is missing, we can't be sure - dump all the pages.  */
+	  should_dump_p = 1;
+	}
+
+      /* Invoke the callback function to create the corefile segment.  */
+      if (should_dump_p)
+	{
+	  func (map.start_address, map.end_address - map.start_address,
+		map.offset, map.inode, map.read, map.write, map.exec,
+		1, /* MODIFIED is true because we want to dump
+		      the mapping.  */
+		map.filename.c_str (), obfd);
+	}
+    }
+
+  return 0;
+}
+
+/* A structure for passing information through
+   linux_find_memory_regions_full.  */
+
+struct linux_find_memory_regions_data
+{
+  /* The original callback.  */
+
+  find_memory_region_ftype func;
+
+  /* The original datum.  */
+
+  void *obfd;
+};
+
+/* A callback for linux_find_memory_regions that converts between the
+   "full"-style callback and find_memory_region_ftype.  */
+
+static int
+linux_find_memory_regions_thunk (ULONGEST vaddr, ULONGEST size,
+				 ULONGEST offset, ULONGEST inode,
+				 int read, int write, int exec, int modified,
+				 const char *filename, void *arg)
+{
+  struct linux_find_memory_regions_data *data
+    = (struct linux_find_memory_regions_data *) arg;
+
+  return data->func (vaddr, size, read, write, exec, modified, data->obfd);
+}
+
+/* A variant of linux_find_memory_regions_full that is suitable as the
+   gdbarch find_memory_regions method.  */
+
+static int
+linux_find_memory_regions (struct gdbarch *gdbarch,
+			   find_memory_region_ftype func, void *obfd)
+{
+  struct linux_find_memory_regions_data data;
+
+  data.func = func;
+  data.obfd = obfd;
+
+  return linux_find_memory_regions_full (gdbarch,
+					 dump_mapping_p,
+					 linux_find_memory_regions_thunk,
+					 &data);
+}
+
+/* This is used to pass information from
+   linux_make_mappings_corefile_notes through
+   linux_find_memory_regions_full.  */
+
+struct linux_make_mappings_data
+{
+  /* Number of files mapped.  */
+  ULONGEST file_count;
+
+  /* The obstack for the main part of the data.  */
+  struct obstack *data_obstack;
+
+  /* The filename obstack.  */
+  struct obstack *filename_obstack;
+
+  /* The architecture's "long" type.  */
+  struct type *long_type;
+};
+
+static linux_find_memory_region_ftype linux_make_mappings_callback;
+
+/* A callback for linux_find_memory_regions_full that updates the
+   mappings data for linux_make_mappings_corefile_notes.  */
+
+static int
+linux_make_mappings_callback (ULONGEST vaddr, ULONGEST size,
+			      ULONGEST offset, ULONGEST inode,
+			      int read, int write, int exec, int modified,
+			      const char *filename, void *data)
+{
+  struct linux_make_mappings_data *map_data
+    = (struct linux_make_mappings_data *) data;
+  gdb_byte buf[sizeof (ULONGEST)];
+
+  if (*filename == '\0' || inode == 0)
+    return 0;
+
+  ++map_data->file_count;
+
+  pack_long (buf, map_data->long_type, vaddr);
+  obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
+  pack_long (buf, map_data->long_type, vaddr + size);
+  obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
+  pack_long (buf, map_data->long_type, offset);
+  obstack_grow (map_data->data_obstack, buf, TYPE_LENGTH (map_data->long_type));
+
+  obstack_grow_str0 (map_data->filename_obstack, filename);
+
+  return 0;
+}
+
+/* Write the file mapping data to the core file, if possible.  OBFD is
+   the output BFD.  NOTE_DATA is the current note data, and NOTE_SIZE
+   is a pointer to the note size.  Updates NOTE_DATA and NOTE_SIZE.  */
+
+static void
+linux_make_mappings_corefile_notes (struct gdbarch *gdbarch, bfd *obfd,
+				    gdb::unique_xmalloc_ptr<char> &note_data,
+				    int *note_size)
+{
+  struct linux_make_mappings_data mapping_data;
+  struct type *long_type
+    = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch), 0, "long");
+  gdb_byte buf[sizeof (ULONGEST)];
+
+  auto_obstack data_obstack, filename_obstack;
+
+  mapping_data.file_count = 0;
+  mapping_data.data_obstack = &data_obstack;
+  mapping_data.filename_obstack = &filename_obstack;
+  mapping_data.long_type = long_type;
+
+  /* Reserve space for the count.  */
+  obstack_blank (&data_obstack, TYPE_LENGTH (long_type));
+  /* We always write the page size as 1 since we have no good way to
+     determine the correct value.  */
+  pack_long (buf, long_type, 1);
+  obstack_grow (&data_obstack, buf, TYPE_LENGTH (long_type));
+
+  linux_find_memory_regions_full (gdbarch, 
+				  dump_note_entry_p,
+				  linux_make_mappings_callback,
+				  &mapping_data);
+
+  if (mapping_data.file_count != 0)
+    {
+      /* Write the count to the obstack.  */
+      pack_long ((gdb_byte *) obstack_base (&data_obstack),
+		 long_type, mapping_data.file_count);
+
+      /* Copy the filenames to the data obstack.  */
+      int size = obstack_object_size (&filename_obstack);
+      obstack_grow (&data_obstack, obstack_base (&filename_obstack),
+		    size);
+
+      note_data.reset (elfcore_write_file_note (obfd, note_data.release (), note_size,
+						obstack_base (&data_obstack),
+						obstack_object_size (&data_obstack)));
+    }
+}
+
+/* Fetch the siginfo data for the specified thread, if it exists.  If
+   there is no data, or we could not read it, return an empty
+   buffer.  */
+
+static gdb::byte_vector
+linux_get_siginfo_data (thread_info *thread, struct gdbarch *gdbarch)
+{
+  struct type *siginfo_type;
+  LONGEST bytes_read;
+
+  if (!gdbarch_get_siginfo_type_p (gdbarch))
+    return gdb::byte_vector ();
+
+  scoped_restore_current_thread save_current_thread;
+  switch_to_thread (thread);
+
+  siginfo_type = gdbarch_get_siginfo_type (gdbarch);
+
+  gdb::byte_vector buf (TYPE_LENGTH (siginfo_type));
+
+  bytes_read = target_read (current_inferior ()->top_target (),
+			    TARGET_OBJECT_SIGNAL_INFO, NULL,
+			    buf.data (), 0, TYPE_LENGTH (siginfo_type));
+  if (bytes_read != TYPE_LENGTH (siginfo_type))
+    buf.clear ();
+
+  return buf;
+}
+
+struct linux_corefile_thread_data
+{
+  linux_corefile_thread_data (struct gdbarch *gdbarch, bfd *obfd,
+			      gdb::unique_xmalloc_ptr<char> &note_data,
+			      int *note_size, gdb_signal stop_signal)
+    : gdbarch (gdbarch), obfd (obfd), note_data (note_data),
+      note_size (note_size), stop_signal (stop_signal)
+  {}
+
+  struct gdbarch *gdbarch;
+  bfd *obfd;
+  gdb::unique_xmalloc_ptr<char> &note_data;
+  int *note_size;
+  enum gdb_signal stop_signal;
+};
+
+/* Records the thread's register state for the corefile note
+   section.  */
+
+static void
+linux_corefile_thread (struct thread_info *info,
+		       struct linux_corefile_thread_data *args)
+{
+  gcore_elf_build_thread_register_notes (args->gdbarch, info,
+					 args->stop_signal,
+					 args->obfd, &args->note_data,
+					 args->note_size);
+
+  /* Don't return anything if we got no register information above,
+     such a core file is useless.  */
+  if (args->note_data != NULL)
+    {
+      gdb::byte_vector siginfo_data
+	= linux_get_siginfo_data (info, args->gdbarch);
+      if (!siginfo_data.empty ())
+	args->note_data.reset (elfcore_write_note (args->obfd,
+						   args->note_data.release (),
+						   args->note_size,
+						   "CORE", NT_SIGINFO,
+						   siginfo_data.data (),
+						   siginfo_data.size ()));
+    }
+}
+
+/* Fill the PRPSINFO structure with information about the process being
+   debugged.  Returns 1 in case of success, 0 for failures.  Please note that
+   even if the structure cannot be entirely filled (e.g., GDB was unable to
+   gather information about the process UID/GID), this function will still
+   return 1 since some information was already recorded.  It will only return
+   0 iff nothing can be gathered.  */
+
+static int
+linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p)
+{
+  /* The filename which we will use to obtain some info about the process.
+     We will basically use this to store the `/proc/PID/FILENAME' file.  */
+  char filename[100];
+  /* The basename of the executable.  */
+  const char *basename;
+  const char *infargs;
+  /* Temporary buffer.  */
+  char *tmpstr;
+  /* The valid states of a process, according to the Linux kernel.  */
+  const char valid_states[] = "RSDTZW";
+  /* The program state.  */
+  const char *prog_state;
+  /* The state of the process.  */
+  char pr_sname;
+  /* The PID of the program which generated the corefile.  */
+  pid_t pid;
+  /* Process flags.  */
+  unsigned int pr_flag;
+  /* Process nice value.  */
+  long pr_nice;
+  /* The number of fields read by `sscanf'.  */
+  int n_fields = 0;
+
+  gdb_assert (p != NULL);
+
+  /* Obtaining PID and filename.  */
+  pid = inferior_ptid.pid ();
+  xsnprintf (filename, sizeof (filename), "/proc/%d/cmdline", (int) pid);
+  /* The full name of the program which generated the corefile.  */
+  gdb::unique_xmalloc_ptr<char> fname
+    = target_fileio_read_stralloc (NULL, filename);
+
+  if (fname == NULL || fname.get ()[0] == '\0')
+    {
+      /* No program name was read, so we won't be able to retrieve more
+	 information about the process.  */
+      return 0;
+    }
+
+  memset (p, 0, sizeof (*p));
+
+  /* Defining the PID.  */
+  p->pr_pid = pid;
+
+  /* Copying the program name.  Only the basename matters.  */
+  basename = lbasename (fname.get ());
+  strncpy (p->pr_fname, basename, sizeof (p->pr_fname) - 1);
+  p->pr_fname[sizeof (p->pr_fname) - 1] = '\0';
+
+  infargs = get_inferior_args ();
+
+  /* The arguments of the program.  */
+  std::string psargs = fname.get ();
+  if (infargs != NULL)
+    psargs = psargs + " " + infargs;
+
+  strncpy (p->pr_psargs, psargs.c_str (), sizeof (p->pr_psargs) - 1);
+  p->pr_psargs[sizeof (p->pr_psargs) - 1] = '\0';
+
+  xsnprintf (filename, sizeof (filename), "/proc/%d/stat", (int) pid);
+  /* The contents of `/proc/PID/stat'.  */
+  gdb::unique_xmalloc_ptr<char> proc_stat_contents
+    = target_fileio_read_stralloc (NULL, filename);
+  char *proc_stat = proc_stat_contents.get ();
+
+  if (proc_stat == NULL || *proc_stat == '\0')
+    {
+      /* Despite being unable to read more information about the
+	 process, we return 1 here because at least we have its
+	 command line, PID and arguments.  */
+      return 1;
+    }
+
+  /* Ok, we have the stats.  It's time to do a little parsing of the
+     contents of the buffer, so that we end up reading what we want.
+
+     The following parsing mechanism is strongly based on the
+     information generated by the `fs/proc/array.c' file, present in
+     the Linux kernel tree.  More details about how the information is
+     displayed can be obtained by seeing the manpage of proc(5),
+     specifically under the entry of `/proc/[pid]/stat'.  */
+
+  /* Getting rid of the PID, since we already have it.  */
+  while (isdigit (*proc_stat))
+    ++proc_stat;
+
+  proc_stat = skip_spaces (proc_stat);
+
+  /* ps command also relies on no trailing fields ever contain ')'.  */
+  proc_stat = strrchr (proc_stat, ')');
+  if (proc_stat == NULL)
+    return 1;
+  proc_stat++;
+
+  proc_stat = skip_spaces (proc_stat);
+
+  n_fields = sscanf (proc_stat,
+		     "%c"		/* Process state.  */
+		     "%d%d%d"		/* Parent PID, group ID, session ID.  */
+		     "%*d%*d"		/* tty_nr, tpgid (not used).  */
+		     "%u"		/* Flags.  */
+		     "%*s%*s%*s%*s"	/* minflt, cminflt, majflt,
+					   cmajflt (not used).  */
+		     "%*s%*s%*s%*s"	/* utime, stime, cutime,
+					   cstime (not used).  */
+		     "%*s"		/* Priority (not used).  */
+		     "%ld",		/* Nice.  */
+		     &pr_sname,
+		     &p->pr_ppid, &p->pr_pgrp, &p->pr_sid,
+		     &pr_flag,
+		     &pr_nice);
+
+  if (n_fields != 6)
+    {
+      /* Again, we couldn't read the complementary information about
+	 the process state.  However, we already have minimal
+	 information, so we just return 1 here.  */
+      return 1;
+    }
+
+  /* Filling the structure fields.  */
+  prog_state = strchr (valid_states, pr_sname);
+  if (prog_state != NULL)
+    p->pr_state = prog_state - valid_states;
+  else
+    {
+      /* Zero means "Running".  */
+      p->pr_state = 0;
+    }
+
+  p->pr_sname = p->pr_state > 5 ? '.' : pr_sname;
+  p->pr_zomb = p->pr_sname == 'Z';
+  p->pr_nice = pr_nice;
+  p->pr_flag = pr_flag;
+
+  /* Finally, obtaining the UID and GID.  For that, we read and parse the
+     contents of the `/proc/PID/status' file.  */
+  xsnprintf (filename, sizeof (filename), "/proc/%d/status", (int) pid);
+  /* The contents of `/proc/PID/status'.  */
+  gdb::unique_xmalloc_ptr<char> proc_status_contents
+    = target_fileio_read_stralloc (NULL, filename);
+  char *proc_status = proc_status_contents.get ();
+
+  if (proc_status == NULL || *proc_status == '\0')
+    {
+      /* Returning 1 since we already have a bunch of information.  */
+      return 1;
+    }
+
+  /* Extracting the UID.  */
+  tmpstr = strstr (proc_status, "Uid:");
+  if (tmpstr != NULL)
+    {
+      /* Advancing the pointer to the beginning of the UID.  */
+      tmpstr += sizeof ("Uid:");
+      while (*tmpstr != '\0' && !isdigit (*tmpstr))
+	++tmpstr;
+
+      if (isdigit (*tmpstr))
+	p->pr_uid = strtol (tmpstr, &tmpstr, 10);
+    }
+
+  /* Extracting the GID.  */
+  tmpstr = strstr (proc_status, "Gid:");
+  if (tmpstr != NULL)
+    {
+      /* Advancing the pointer to the beginning of the GID.  */
+      tmpstr += sizeof ("Gid:");
+      while (*tmpstr != '\0' && !isdigit (*tmpstr))
+	++tmpstr;
+
+      if (isdigit (*tmpstr))
+	p->pr_gid = strtol (tmpstr, &tmpstr, 10);
+    }
+
+  return 1;
+}
+
+/* Build the note section for a corefile, and return it in a malloc
+   buffer.  */
+
+static gdb::unique_xmalloc_ptr<char>
+linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
+{
+  struct elf_internal_linux_prpsinfo prpsinfo;
+  gdb::unique_xmalloc_ptr<char> note_data;
+
+  if (! gdbarch_iterate_over_regset_sections_p (gdbarch))
+    return NULL;
+
+  if (linux_fill_prpsinfo (&prpsinfo))
+    {
+      if (gdbarch_ptr_bit (gdbarch) == 64)
+	note_data.reset (elfcore_write_linux_prpsinfo64 (obfd,
+							 note_data.release (),
+							 note_size, &prpsinfo));
+      else
+	note_data.reset (elfcore_write_linux_prpsinfo32 (obfd,
+							 note_data.release (),
+							 note_size, &prpsinfo));
+    }
+
+  /* Thread register information.  */
+  try
+    {
+      update_thread_list ();
+    }
+  catch (const gdb_exception_error &e)
+    {
+      exception_print (gdb_stderr, e);
+    }
+
+  /* Like the kernel, prefer dumping the signalled thread first.
+     "First thread" is what tools use to infer the signalled
+     thread.  */
+  thread_info *signalled_thr = gcore_find_signalled_thread ();
+  gdb_signal stop_signal;
+  if (signalled_thr != nullptr)
+    stop_signal = signalled_thr->suspend.stop_signal;
+  else
+    stop_signal = GDB_SIGNAL_0;
+
+  linux_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
+					  stop_signal);
+
+  if (signalled_thr != nullptr)
+    linux_corefile_thread (signalled_thr, &thread_args);
+  for (thread_info *thr : current_inferior ()->non_exited_threads ())
+    {
+      if (thr == signalled_thr)
+	continue;
+
+      linux_corefile_thread (thr, &thread_args);
+    }
+
+  if (!note_data)
+    return NULL;
+
+  /* Auxillary vector.  */
+  gdb::optional<gdb::byte_vector> auxv =
+    target_read_alloc (current_inferior ()->top_target (),
+		       TARGET_OBJECT_AUXV, NULL);
+  if (auxv && !auxv->empty ())
+    {
+      note_data.reset (elfcore_write_note (obfd, note_data.release (),
+					   note_size, "CORE", NT_AUXV,
+					   auxv->data (), auxv->size ()));
+
+      if (!note_data)
+	return NULL;
+    }
+
+  /* File mappings.  */
+  linux_make_mappings_corefile_notes (gdbarch, obfd, note_data, note_size);
+
+  /* Target description.  */
+  gcore_elf_make_tdesc_note (obfd, &note_data, note_size);
+
+  return note_data;
+}
+
+/* Implementation of `gdbarch_gdb_signal_from_target', as defined in
+   gdbarch.h.  This function is not static because it is exported to
+   other -tdep files.  */
+
+enum gdb_signal
+linux_gdb_signal_from_target (struct gdbarch *gdbarch, int signal)
+{
+  switch (signal)
+    {
+    case 0:
+      return GDB_SIGNAL_0;
+
+    case LINUX_SIGHUP:
+      return GDB_SIGNAL_HUP;
+
+    case LINUX_SIGINT:
+      return GDB_SIGNAL_INT;
+
+    case LINUX_SIGQUIT:
+      return GDB_SIGNAL_QUIT;
+
+    case LINUX_SIGILL:
+      return GDB_SIGNAL_ILL;
+
+    case LINUX_SIGTRAP:
+      return GDB_SIGNAL_TRAP;
+
+    case LINUX_SIGABRT:
+      return GDB_SIGNAL_ABRT;
+
+    case LINUX_SIGBUS:
+      return GDB_SIGNAL_BUS;
+
+    case LINUX_SIGFPE:
+      return GDB_SIGNAL_FPE;
+
+    case LINUX_SIGKILL:
+      return GDB_SIGNAL_KILL;
+
+    case LINUX_SIGUSR1:
+      return GDB_SIGNAL_USR1;
+
+    case LINUX_SIGSEGV:
+      return GDB_SIGNAL_SEGV;
+
+    case LINUX_SIGUSR2:
+      return GDB_SIGNAL_USR2;
+
+    case LINUX_SIGPIPE:
+      return GDB_SIGNAL_PIPE;
+
+    case LINUX_SIGALRM:
+      return GDB_SIGNAL_ALRM;
+
+    case LINUX_SIGTERM:
+      return GDB_SIGNAL_TERM;
+
+    case LINUX_SIGCHLD:
+      return GDB_SIGNAL_CHLD;
+
+    case LINUX_SIGCONT:
+      return GDB_SIGNAL_CONT;
+
+    case LINUX_SIGSTOP:
+      return GDB_SIGNAL_STOP;
+
+    case LINUX_SIGTSTP:
+      return GDB_SIGNAL_TSTP;
+
+    case LINUX_SIGTTIN:
+      return GDB_SIGNAL_TTIN;
+
+    case LINUX_SIGTTOU:
+      return GDB_SIGNAL_TTOU;
+
+    case LINUX_SIGURG:
+      return GDB_SIGNAL_URG;
+
+    case LINUX_SIGXCPU:
+      return GDB_SIGNAL_XCPU;
+
+    case LINUX_SIGXFSZ:
+      return GDB_SIGNAL_XFSZ;
+
+    case LINUX_SIGVTALRM:
+      return GDB_SIGNAL_VTALRM;
+
+    case LINUX_SIGPROF:
+      return GDB_SIGNAL_PROF;
+
+    case LINUX_SIGWINCH:
+      return GDB_SIGNAL_WINCH;
+
+    /* No way to differentiate between SIGIO and SIGPOLL.
+       Therefore, we just handle the first one.  */
+    case LINUX_SIGIO:
+      return GDB_SIGNAL_IO;
+
+    case LINUX_SIGPWR:
+      return GDB_SIGNAL_PWR;
+
+    case LINUX_SIGSYS:
+      return GDB_SIGNAL_SYS;
+
+    /* SIGRTMIN and SIGRTMAX are not continuous in <gdb/signals.def>,
+       therefore we have to handle them here.  */
+    case LINUX_SIGRTMIN:
+      return GDB_SIGNAL_REALTIME_32;
+
+    case LINUX_SIGRTMAX:
+      return GDB_SIGNAL_REALTIME_64;
+    }
+
+  if (signal >= LINUX_SIGRTMIN + 1 && signal <= LINUX_SIGRTMAX - 1)
+    {
+      int offset = signal - LINUX_SIGRTMIN + 1;
+
+      return (enum gdb_signal) ((int) GDB_SIGNAL_REALTIME_33 + offset);
+    }
+
+  return GDB_SIGNAL_UNKNOWN;
+}
+
+/* Implementation of `gdbarch_gdb_signal_to_target', as defined in
+   gdbarch.h.  This function is not static because it is exported to
+   other -tdep files.  */
+
+int
+linux_gdb_signal_to_target (struct gdbarch *gdbarch,
+			    enum gdb_signal signal)
+{
+  switch (signal)
+    {
+    case GDB_SIGNAL_0:
+      return 0;
+
+    case GDB_SIGNAL_HUP:
+      return LINUX_SIGHUP;
+
+    case GDB_SIGNAL_INT:
+      return LINUX_SIGINT;
+
+    case GDB_SIGNAL_QUIT:
+      return LINUX_SIGQUIT;
+
+    case GDB_SIGNAL_ILL:
+      return LINUX_SIGILL;
+
+    case GDB_SIGNAL_TRAP:
+      return LINUX_SIGTRAP;
+
+    case GDB_SIGNAL_ABRT:
+      return LINUX_SIGABRT;
+
+    case GDB_SIGNAL_FPE:
+      return LINUX_SIGFPE;
+
+    case GDB_SIGNAL_KILL:
+      return LINUX_SIGKILL;
+
+    case GDB_SIGNAL_BUS:
+      return LINUX_SIGBUS;
+
+    case GDB_SIGNAL_SEGV:
+      return LINUX_SIGSEGV;
+
+    case GDB_SIGNAL_SYS:
+      return LINUX_SIGSYS;
+
+    case GDB_SIGNAL_PIPE:
+      return LINUX_SIGPIPE;
+
+    case GDB_SIGNAL_ALRM:
+      return LINUX_SIGALRM;
+
+    case GDB_SIGNAL_TERM:
+      return LINUX_SIGTERM;
+
+    case GDB_SIGNAL_URG:
+      return LINUX_SIGURG;
+
+    case GDB_SIGNAL_STOP:
+      return LINUX_SIGSTOP;
+
+    case GDB_SIGNAL_TSTP:
+      return LINUX_SIGTSTP;
+
+    case GDB_SIGNAL_CONT:
+      return LINUX_SIGCONT;
+
+    case GDB_SIGNAL_CHLD:
+      return LINUX_SIGCHLD;
+
+    case GDB_SIGNAL_TTIN:
+      return LINUX_SIGTTIN;
+
+    case GDB_SIGNAL_TTOU:
+      return LINUX_SIGTTOU;
+
+    case GDB_SIGNAL_IO:
+      return LINUX_SIGIO;
+
+    case GDB_SIGNAL_XCPU:
+      return LINUX_SIGXCPU;
+
+    case GDB_SIGNAL_XFSZ:
+      return LINUX_SIGXFSZ;
+
+    case GDB_SIGNAL_VTALRM:
+      return LINUX_SIGVTALRM;
+
+    case GDB_SIGNAL_PROF:
+      return LINUX_SIGPROF;
+
+    case GDB_SIGNAL_WINCH:
+      return LINUX_SIGWINCH;
+
+    case GDB_SIGNAL_USR1:
+      return LINUX_SIGUSR1;
+
+    case GDB_SIGNAL_USR2:
+      return LINUX_SIGUSR2;
+
+    case GDB_SIGNAL_PWR:
+      return LINUX_SIGPWR;
+
+    case GDB_SIGNAL_POLL:
+      return LINUX_SIGPOLL;
+
+    /* GDB_SIGNAL_REALTIME_32 is not continuous in <gdb/signals.def>,
+       therefore we have to handle it here.  */
+    case GDB_SIGNAL_REALTIME_32:
+      return LINUX_SIGRTMIN;
+
+    /* Same comment applies to _64.  */
+    case GDB_SIGNAL_REALTIME_64:
+      return LINUX_SIGRTMAX;
+    }
+
+  /* GDB_SIGNAL_REALTIME_33 to _64 are continuous.  */
+  if (signal >= GDB_SIGNAL_REALTIME_33
+      && signal <= GDB_SIGNAL_REALTIME_63)
+    {
+      int offset = signal - GDB_SIGNAL_REALTIME_33;
+
+      return LINUX_SIGRTMIN + 1 + offset;
+    }
+
+  return -1;
+}
+
+/* Helper for linux_vsyscall_range that does the real work of finding
+   the vsyscall's address range.  */
+
+static int
+linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
+{
+  char filename[100];
+  long pid;
+
+  if (target_auxv_search (current_inferior ()->top_target (),
+			  AT_SYSINFO_EHDR, &range->start) <= 0)
+    return 0;
+
+  /* It doesn't make sense to access the host's /proc when debugging a
+     core file.  Instead, look for the PT_LOAD segment that matches
+     the vDSO.  */
+  if (!target_has_execution ())
+    {
+      long phdrs_size;
+      int num_phdrs, i;
+
+      phdrs_size = bfd_get_elf_phdr_upper_bound (core_bfd);
+      if (phdrs_size == -1)
+	return 0;
+
+      gdb::unique_xmalloc_ptr<Elf_Internal_Phdr>
+	phdrs ((Elf_Internal_Phdr *) xmalloc (phdrs_size));
+      num_phdrs = bfd_get_elf_phdrs (core_bfd, phdrs.get ());
+      if (num_phdrs == -1)
+	return 0;
+
+      for (i = 0; i < num_phdrs; i++)
+	if (phdrs.get ()[i].p_type == PT_LOAD
+	    && phdrs.get ()[i].p_vaddr == range->start)
+	  {
+	    range->length = phdrs.get ()[i].p_memsz;
+	    return 1;
+	  }
+
+      return 0;
+    }
+
+  /* We need to know the real target PID to access /proc.  */
+  if (current_inferior ()->fake_pid_p)
+    return 0;
+
+  pid = current_inferior ()->pid;
+
+  /* Note that reading /proc/PID/task/PID/maps (1) is much faster than
+     reading /proc/PID/maps (2).  The later identifies thread stacks
+     in the output, which requires scanning every thread in the thread
+     group to check whether a VMA is actually a thread's stack.  With
+     Linux 4.4 on an Intel i7-4810MQ @ 2.80GHz, with an inferior with
+     a few thousand threads, (1) takes a few miliseconds, while (2)
+     takes several seconds.  Also note that "smaps", what we read for
+     determining core dump mappings, is even slower than "maps".  */
+  xsnprintf (filename, sizeof filename, "/proc/%ld/task/%ld/maps", pid, pid);
+  gdb::unique_xmalloc_ptr<char> data
+    = target_fileio_read_stralloc (NULL, filename);
+  if (data != NULL)
+    {
+      char *line;
+      char *saveptr = NULL;
+
+      for (line = strtok_r (data.get (), "\n", &saveptr);
+	   line != NULL;
+	   line = strtok_r (NULL, "\n", &saveptr))
+	{
+	  ULONGEST addr, endaddr;
+	  const char *p = line;
+
+	  addr = strtoulst (p, &p, 16);
+	  if (addr == range->start)
+	    {
+	      if (*p == '-')
+		p++;
+	      endaddr = strtoulst (p, &p, 16);
+	      range->length = endaddr - addr;
+	      return 1;
+	    }
+	}
+    }
+  else
+    warning (_("unable to open /proc file '%s'"), filename);
+
+  return 0;
+}
+
+/* Implementation of the "vsyscall_range" gdbarch hook.  Handles
+   caching, and defers the real work to linux_vsyscall_range_raw.  */
+
+static int
+linux_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
+{
+  struct linux_info *info = get_linux_inferior_data (current_inferior ());
+
+  if (info->vsyscall_range_p == 0)
+    {
+      if (linux_vsyscall_range_raw (gdbarch, &info->vsyscall_range))
+	info->vsyscall_range_p = 1;
+      else
+	info->vsyscall_range_p = -1;
+    }
+
+  if (info->vsyscall_range_p < 0)
+    return 0;
+
+  *range = info->vsyscall_range;
+  return 1;
+}
+
+/* Symbols for linux_infcall_mmap's ARG_FLAGS; their Linux MAP_* system
+   definitions would be dependent on compilation host.  */
+#define GDB_MMAP_MAP_PRIVATE	0x02		/* Changes are private.  */
+#define GDB_MMAP_MAP_ANONYMOUS	0x20		/* Don't use a file.  */
+
+/* See gdbarch.sh 'infcall_mmap'.  */
+
+static CORE_ADDR
+linux_infcall_mmap (CORE_ADDR size, unsigned prot)
+{
+  struct objfile *objf;
+  /* Do there still exist any Linux systems without "mmap64"?
+     "mmap" uses 64-bit off_t on x86_64 and 32-bit off_t on i386 and x32.  */
+  struct value *mmap_val = find_function_in_inferior ("mmap64", &objf);
+  struct value *addr_val;
+  struct gdbarch *gdbarch = objf->arch ();
+  CORE_ADDR retval;
+  enum
+    {
+      ARG_ADDR, ARG_LENGTH, ARG_PROT, ARG_FLAGS, ARG_FD, ARG_OFFSET, ARG_LAST
+    };
+  struct value *arg[ARG_LAST];
+
+  arg[ARG_ADDR] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr,
+				      0);
+  /* Assuming sizeof (unsigned long) == sizeof (size_t).  */
+  arg[ARG_LENGTH] = value_from_ulongest
+		    (builtin_type (gdbarch)->builtin_unsigned_long, size);
+  gdb_assert ((prot & ~(GDB_MMAP_PROT_READ | GDB_MMAP_PROT_WRITE
+			| GDB_MMAP_PROT_EXEC))
+	      == 0);
+  arg[ARG_PROT] = value_from_longest (builtin_type (gdbarch)->builtin_int, prot);
+  arg[ARG_FLAGS] = value_from_longest (builtin_type (gdbarch)->builtin_int,
+				       GDB_MMAP_MAP_PRIVATE
+				       | GDB_MMAP_MAP_ANONYMOUS);
+  arg[ARG_FD] = value_from_longest (builtin_type (gdbarch)->builtin_int, -1);
+  arg[ARG_OFFSET] = value_from_longest (builtin_type (gdbarch)->builtin_int64,
+					0);
+  addr_val = call_function_by_hand (mmap_val, NULL, arg);
+  retval = value_as_address (addr_val);
+  if (retval == (CORE_ADDR) -1)
+    error (_("Failed inferior mmap call for %s bytes, errno is changed."),
+	   pulongest (size));
+  return retval;
+}
+
+/* See gdbarch.sh 'infcall_munmap'.  */
+
+static void
+linux_infcall_munmap (CORE_ADDR addr, CORE_ADDR size)
+{
+  struct objfile *objf;
+  struct value *munmap_val = find_function_in_inferior ("munmap", &objf);
+  struct value *retval_val;
+  struct gdbarch *gdbarch = objf->arch ();
+  LONGEST retval;
+  enum
+    {
+      ARG_ADDR, ARG_LENGTH, ARG_LAST
+    };
+  struct value *arg[ARG_LAST];
+
+  arg[ARG_ADDR] = value_from_pointer (builtin_type (gdbarch)->builtin_data_ptr,
+				      addr);
+  /* Assuming sizeof (unsigned long) == sizeof (size_t).  */
+  arg[ARG_LENGTH] = value_from_ulongest
+		    (builtin_type (gdbarch)->builtin_unsigned_long, size);
+  retval_val = call_function_by_hand (munmap_val, NULL, arg);
+  retval = value_as_long (retval_val);
+  if (retval != 0)
+    warning (_("Failed inferior munmap call at %s for %s bytes, "
+	       "errno is changed."),
+	     hex_string (addr), pulongest (size));
+}
+
+/* See linux-tdep.h.  */
+
+CORE_ADDR
+linux_displaced_step_location (struct gdbarch *gdbarch)
+{
+  CORE_ADDR addr;
+  int bp_len;
+
+  /* Determine entry point from target auxiliary vector.  This avoids
+     the need for symbols.  Also, when debugging a stand-alone SPU
+     executable, entry_point_address () will point to an SPU
+     local-store address and is thus not usable as displaced stepping
+     location.  The auxiliary vector gets us the PowerPC-side entry
+     point address instead.  */
+  if (target_auxv_search (current_inferior ()->top_target (),
+			  AT_ENTRY, &addr) <= 0)
+    throw_error (NOT_SUPPORTED_ERROR,
+		 _("Cannot find AT_ENTRY auxiliary vector entry."));
+
+  /* Make certain that the address points at real code, and not a
+     function descriptor.  */
+  addr = gdbarch_convert_from_func_ptr_addr
+    (gdbarch, addr, current_inferior ()->top_target ());
+
+  /* Inferior calls also use the entry point as a breakpoint location.
+     We don't want displaced stepping to interfere with those
+     breakpoints, so leave space.  */
+  gdbarch_breakpoint_from_pc (gdbarch, &addr, &bp_len);
+  addr += bp_len * 2;
+
+  return addr;
+}
+
+/* See linux-tdep.h.  */
+
+displaced_step_prepare_status
+linux_displaced_step_prepare (gdbarch *arch, thread_info *thread,
+			      CORE_ADDR &displaced_pc)
+{
+  linux_info *per_inferior = get_linux_inferior_data (thread->inf);
+
+  if (!per_inferior->disp_step_bufs.has_value ())
+    {
+      /* Figure out the location of the buffers.  They are contiguous, starting
+	 at DISP_STEP_BUF_ADDR.  They are all of size BUF_LEN.  */
+      CORE_ADDR disp_step_buf_addr
+	= linux_displaced_step_location (thread->inf->gdbarch);
+      int buf_len = gdbarch_max_insn_length (arch);
+
+      linux_gdbarch_data *gdbarch_data = get_linux_gdbarch_data (arch);
+      gdb_assert (gdbarch_data->num_disp_step_buffers > 0);
+
+      std::vector<CORE_ADDR> buffers;
+      for (int i = 0; i < gdbarch_data->num_disp_step_buffers; i++)
+	buffers.push_back (disp_step_buf_addr + i * buf_len);
+
+      per_inferior->disp_step_bufs.emplace (buffers);
+    }
+
+  return per_inferior->disp_step_bufs->prepare (thread, displaced_pc);
+}
+
+/* See linux-tdep.h.  */
+
+displaced_step_finish_status
+linux_displaced_step_finish (gdbarch *arch, thread_info *thread, gdb_signal sig)
+{
+  linux_info *per_inferior = get_linux_inferior_data (thread->inf);
+
+  gdb_assert (per_inferior->disp_step_bufs.has_value ());
+
+  return per_inferior->disp_step_bufs->finish (arch, thread, sig);
+}
+
+/* See linux-tdep.h.  */
+
+const displaced_step_copy_insn_closure *
+linux_displaced_step_copy_insn_closure_by_addr (inferior *inf, CORE_ADDR addr)
+{
+  linux_info *per_inferior = linux_inferior_data.get (inf);
+
+  if (per_inferior == nullptr
+      || !per_inferior->disp_step_bufs.has_value ())
+    return nullptr;
+
+  return per_inferior->disp_step_bufs->copy_insn_closure_by_addr (addr);
+}
+
+/* See linux-tdep.h.  */
+
+void
+linux_displaced_step_restore_all_in_ptid (inferior *parent_inf, ptid_t ptid)
+{
+  linux_info *per_inferior = linux_inferior_data.get (parent_inf);
+
+  if (per_inferior == nullptr
+      || !per_inferior->disp_step_bufs.has_value ())
+    return;
+
+  per_inferior->disp_step_bufs->restore_in_ptid (ptid);
+}
+
+/* See linux-tdep.h.  */
+
+CORE_ADDR
+linux_get_hwcap (struct target_ops *target)
+{
+  CORE_ADDR field;
+  if (target_auxv_search (target, AT_HWCAP, &field) != 1)
+    return 0;
+  return field;
+}
+
+/* See linux-tdep.h.  */
+
+CORE_ADDR
+linux_get_hwcap2 (struct target_ops *target)
+{
+  CORE_ADDR field;
+  if (target_auxv_search (target, AT_HWCAP2, &field) != 1)
+    return 0;
+  return field;
+}
+
+/* Display whether the gcore command is using the
+   /proc/PID/coredump_filter file.  */
+
+static void
+show_use_coredump_filter (struct ui_file *file, int from_tty,
+			  struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Use of /proc/PID/coredump_filter file to generate"
+			    " corefiles is %s.\n"), value);
+}
+
+/* Display whether the gcore command is dumping mappings marked with
+   the VM_DONTDUMP flag.  */
+
+static void
+show_dump_excluded_mappings (struct ui_file *file, int from_tty,
+			     struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Dumping of mappings marked with the VM_DONTDUMP"
+			    " flag is %s.\n"), value);
+}
+
+/* To be called from the various GDB_OSABI_LINUX handlers for the
+   various GNU/Linux architectures and machine types.
+
+   NUM_DISP_STEP_BUFFERS is the number of displaced step buffers to use.  If 0,
+   displaced stepping is not supported. */
+
+void
+linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
+		int num_disp_step_buffers)
+{
+  if (num_disp_step_buffers > 0)
+    {
+      linux_gdbarch_data *gdbarch_data = get_linux_gdbarch_data (gdbarch);
+      gdbarch_data->num_disp_step_buffers = num_disp_step_buffers;
+
+      set_gdbarch_displaced_step_prepare (gdbarch,
+					  linux_displaced_step_prepare);
+      set_gdbarch_displaced_step_finish (gdbarch, linux_displaced_step_finish);
+      set_gdbarch_displaced_step_copy_insn_closure_by_addr
+	(gdbarch, linux_displaced_step_copy_insn_closure_by_addr);
+      set_gdbarch_displaced_step_restore_all_in_ptid
+	(gdbarch, linux_displaced_step_restore_all_in_ptid);
+    }
+
+  set_gdbarch_core_pid_to_str (gdbarch, linux_core_pid_to_str);
+  set_gdbarch_info_proc (gdbarch, linux_info_proc);
+  set_gdbarch_core_info_proc (gdbarch, linux_core_info_proc);
+  set_gdbarch_core_xfer_siginfo (gdbarch, linux_core_xfer_siginfo);
+  set_gdbarch_read_core_file_mappings (gdbarch, linux_read_core_file_mappings);
+  set_gdbarch_find_memory_regions (gdbarch, linux_find_memory_regions);
+  set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes);
+  set_gdbarch_has_shared_address_space (gdbarch,
+					linux_has_shared_address_space);
+  set_gdbarch_gdb_signal_from_target (gdbarch,
+				      linux_gdb_signal_from_target);
+  set_gdbarch_gdb_signal_to_target (gdbarch,
+				    linux_gdb_signal_to_target);
+  set_gdbarch_vsyscall_range (gdbarch, linux_vsyscall_range);
+  set_gdbarch_infcall_mmap (gdbarch, linux_infcall_mmap);
+  set_gdbarch_infcall_munmap (gdbarch, linux_infcall_munmap);
+  set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+}
+
+void _initialize_linux_tdep ();
+void
+_initialize_linux_tdep ()
+{
+  linux_gdbarch_data_handle =
+    gdbarch_data_register_pre_init (init_linux_gdbarch_data);
+
+  /* Observers used to invalidate the cache when needed.  */
+  gdb::observers::inferior_exit.attach (invalidate_linux_cache_inf,
+					"linux-tdep");
+  gdb::observers::inferior_appeared.attach (invalidate_linux_cache_inf,
+					    "linux-tdep");
+  gdb::observers::inferior_execd.attach (invalidate_linux_cache_inf,
+					 "linux-tdep");
+
+  add_setshow_boolean_cmd ("use-coredump-filter", class_files,
+			   &use_coredump_filter, _("\
+Set whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Show whether gcore should consider /proc/PID/coredump_filter."),
+			   _("\
+Use this command to set whether gcore should consider the contents\n\
+of /proc/PID/coredump_filter when generating the corefile.  For more information\n\
+about this file, refer to the manpage of core(5)."),
+			   NULL, show_use_coredump_filter,
+			   &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("dump-excluded-mappings", class_files,
+			   &dump_excluded_mappings, _("\
+Set whether gcore should dump mappings marked with the VM_DONTDUMP flag."),
+			   _("\
+Show whether gcore should dump mappings marked with the VM_DONTDUMP flag."),
+			   _("\
+Use this command to set whether gcore should dump mappings marked with the\n\
+VM_DONTDUMP flag (\"dd\" in /proc/PID/smaps) when generating the corefile.  For\n\
+more information about this file, refer to the manpage of proc(5) and core(5)."),
+			   NULL, show_dump_excluded_mappings,
+			   &setlist, &showlist);
+}
diff -Naur gdb-11.2.orig/gdb/linux-tdep.h gdb-11.2/gdb/linux-tdep.h
--- gdb-11.2.orig/gdb/linux-tdep.h	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/linux-tdep.h	2022-02-06 14:36:56.658215673 -0600
@@ -98,4 +98,9 @@
    error, 0 is returned.  */
 extern CORE_ADDR linux_get_hwcap2 (struct target_ops *target);
 
+/* Fetch (and possibly build) an appropriate `struct link_map_offsets'
+   for ILP32 and LP64 Linux systems.  */
+extern struct link_map_offsets *linux_ilp32_fetch_link_map_offsets ();
+extern struct link_map_offsets *linux_lp64_fetch_link_map_offsets ();
+
 #endif /* linux-tdep.h */
diff -Naur gdb-11.2.orig/gdb/m32r-linux-tdep.c gdb-11.2/gdb/m32r-linux-tdep.c
--- gdb-11.2.orig/gdb/m32r-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/m32r-linux-tdep.c	2022-02-06 14:36:56.658215673 -0600
@@ -461,7 +461,7 @@
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 
   /* Core file support.  */
   set_gdbarch_iterate_over_regset_sections
diff -Naur gdb-11.2.orig/gdb/m68k-linux-tdep.c gdb-11.2/gdb/m68k-linux-tdep.c
--- gdb-11.2.orig/gdb/m68k-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/m68k-linux-tdep.c	2022-02-06 14:36:56.658215673 -0600
@@ -408,7 +408,7 @@
 
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_ilp32_fetch_link_map_offsets);
+					 linux_ilp32_fetch_link_map_offsets);
 
   /* GNU/Linux uses the dynamic linker included in the GNU C Library.  */
   set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
diff -Naur gdb-11.2.orig/gdb/microblaze-linux-tdep.c gdb-11.2/gdb/microblaze-linux-tdep.c
--- gdb-11.2.orig/gdb/microblaze-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/microblaze-linux-tdep.c	2022-02-06 14:36:56.658215673 -0600
@@ -124,7 +124,7 @@
 
   /* Shared library handling.  */
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_ilp32_fetch_link_map_offsets);
+					 linux_ilp32_fetch_link_map_offsets);
 
   /* Trampolines.  */
   tramp_frame_prepend_unwinder (gdbarch,
diff -Naur gdb-11.2.orig/gdb/mips-linux-tdep.c gdb-11.2/gdb/mips-linux-tdep.c
--- gdb-11.2.orig/gdb/mips-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/mips-linux-tdep.c	2022-02-06 14:36:56.658215673 -0600
@@ -1542,7 +1542,7 @@
 	set_gdbarch_get_longjmp_target (gdbarch,
 					mips_linux_get_longjmp_target);
 	set_solib_svr4_fetch_link_map_offsets
-	  (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+	  (gdbarch, linux_ilp32_fetch_link_map_offsets);
 	tramp_frame_prepend_unwinder (gdbarch, &micromips_linux_o32_sigframe);
 	tramp_frame_prepend_unwinder (gdbarch,
 				      &micromips_linux_o32_rt_sigframe);
@@ -1554,7 +1554,7 @@
 	set_gdbarch_get_longjmp_target (gdbarch,
 					mips_linux_get_longjmp_target);
 	set_solib_svr4_fetch_link_map_offsets
-	  (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+	  (gdbarch, linux_ilp32_fetch_link_map_offsets);
 	set_gdbarch_long_double_bit (gdbarch, 128);
 	/* These floatformats should probably be renamed.  MIPS uses
 	   the same 128-bit IEEE floating point format that IA-64 uses,
@@ -1570,7 +1570,7 @@
 	set_gdbarch_get_longjmp_target (gdbarch,
 					mips64_linux_get_longjmp_target);
 	set_solib_svr4_fetch_link_map_offsets
-	  (gdbarch, svr4_lp64_fetch_link_map_offsets);
+	  (gdbarch, linux_lp64_fetch_link_map_offsets);
 	set_gdbarch_long_double_bit (gdbarch, 128);
 	/* These floatformats should probably be renamed.  MIPS uses
 	   the same 128-bit IEEE floating point format that IA-64 uses,
diff -Naur gdb-11.2.orig/gdb/mn10300-linux-tdep.c gdb-11.2/gdb/mn10300-linux-tdep.c
--- gdb-11.2.orig/gdb/mn10300-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/mn10300-linux-tdep.c	2022-02-06 14:36:56.658215673 -0600
@@ -709,7 +709,7 @@
   set_gdbarch_iterate_over_regset_sections
     (gdbarch, am33_iterate_over_regset_sections);
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 
   tramp_frame_prepend_unwinder (gdbarch, &am33_linux_sigframe);
   tramp_frame_prepend_unwinder (gdbarch, &am33_linux_rt_sigframe);
diff -Naur gdb-11.2.orig/gdb/nios2-linux-tdep.c gdb-11.2/gdb/nios2-linux-tdep.c
--- gdb-11.2.orig/gdb/nios2-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/nios2-linux-tdep.c	2022-02-06 14:36:56.658215673 -0600
@@ -226,7 +226,7 @@
   set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_ilp32_fetch_link_map_offsets);
+					 linux_ilp32_fetch_link_map_offsets);
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
 					     svr4_fetch_objfile_link_map);
diff -Naur gdb-11.2.orig/gdb/or1k-linux-tdep.c gdb-11.2/gdb/or1k-linux-tdep.c
--- gdb-11.2.orig/gdb/or1k-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/or1k-linux-tdep.c	2022-02-06 14:36:56.658215673 -0600
@@ -143,7 +143,7 @@
   linux_init_abi (info, gdbarch, 0);
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_ilp32_fetch_link_map_offsets);
+					 linux_ilp32_fetch_link_map_offsets);
 
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
diff -Naur gdb-11.2.orig/gdb/ppc-linux-tdep.c gdb-11.2/gdb/ppc-linux-tdep.c
--- gdb-11.2.orig/gdb/ppc-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/ppc-linux-tdep.c	2022-02-06 14:36:56.659215682 -0600
@@ -2035,7 +2035,7 @@
       /* Shared library handling.  */
       set_gdbarch_skip_trampoline_code (gdbarch, ppc_skip_trampoline_code);
       set_solib_svr4_fetch_link_map_offsets
-	(gdbarch, svr4_ilp32_fetch_link_map_offsets);
+	(gdbarch, linux_ilp32_fetch_link_map_offsets);
 
       /* Setting the correct XML syscall filename.  */
       set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_PPC);
@@ -2087,7 +2087,7 @@
       /* Shared library handling.  */
       set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
       set_solib_svr4_fetch_link_map_offsets
-	(gdbarch, svr4_lp64_fetch_link_map_offsets);
+	(gdbarch, linux_lp64_fetch_link_map_offsets);
 
       /* Setting the correct XML syscall filename.  */
       set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_PPC64);
diff -Naur gdb-11.2.orig/gdb/riscv-linux-tdep.c gdb-11.2/gdb/riscv-linux-tdep.c
--- gdb-11.2.orig/gdb/riscv-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/riscv-linux-tdep.c	2022-02-06 14:36:56.659215682 -0600
@@ -165,8 +165,8 @@
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
 					 (riscv_isa_xlen (gdbarch) == 4
-					  ? svr4_ilp32_fetch_link_map_offsets
-					  : svr4_lp64_fetch_link_map_offsets));
+					  ? linux_ilp32_fetch_link_map_offsets
+					  : linux_lp64_fetch_link_map_offsets));
 
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
diff -Naur gdb-11.2.orig/gdb/riscv-linux-tdep.c.orig gdb-11.2/gdb/riscv-linux-tdep.c.orig
--- gdb-11.2.orig/gdb/riscv-linux-tdep.c.orig	1969-12-31 18:00:00.000000000 -0600
+++ gdb-11.2/gdb/riscv-linux-tdep.c.orig	2022-01-16 05:21:18.000000000 -0600
@@ -0,0 +1,195 @@
+/* Target-dependent code for GNU/Linux on RISC-V processors.
+   Copyright (C) 2018-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 "riscv-tdep.h"
+#include "osabi.h"
+#include "glibc-tdep.h"
+#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.
+   Registers x1 to x31 are in the same place.  */
+
+static const struct regcache_map_entry riscv_linux_gregmap[] =
+{
+  { 1,  RISCV_PC_REGNUM, 0 },
+  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
+  { 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 =
+{
+  riscv_linux_gregmap, riscv_supply_regset, regcache_collect_regset
+};
+
+/* Define the FP register regset.  */
+
+static const struct regset riscv_linux_fregset =
+{
+  riscv_linux_fregmap, riscv_supply_regset, regcache_collect_regset
+};
+
+/* Define hook for core file support.  */
+
+static void
+riscv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					  iterate_over_regset_sections_cb *cb,
+					  void *cb_data,
+					  const struct regcache *regcache)
+{
+  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;
+   }; */
+
+#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.  */
+
+static void
+riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  linux_init_abi (info, gdbarch, 0);
+
+  set_gdbarch_software_single_step (gdbarch, riscv_software_single_step);
+
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					 (riscv_isa_xlen (gdbarch) == 4
+					  ? svr4_ilp32_fetch_link_map_offsets
+					  : svr4_lp64_fetch_link_map_offsets));
+
+  /* GNU/Linux uses SVR4-style shared libraries.  */
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+
+  /* GNU/Linux uses the dynamic linker included in the GNU C Library.  */
+  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+
+  /* Enable TLS support.  */
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+					     svr4_fetch_objfile_link_map);
+
+  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 ()
+{
+  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_LINUX,
+			  riscv_linux_init_abi);
+}
diff -Naur gdb-11.2.orig/gdb/s390-linux-tdep.c gdb-11.2/gdb/s390-linux-tdep.c
--- gdb-11.2.orig/gdb/s390-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/s390-linux-tdep.c	2022-02-06 14:36:56.659215682 -0600
@@ -1158,7 +1158,7 @@
   s390_linux_init_abi_any (info, gdbarch);
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_ilp32_fetch_link_map_offsets);
+					 linux_ilp32_fetch_link_map_offsets);
   set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_S390);
 }
 
@@ -1174,7 +1174,7 @@
   s390_linux_init_abi_any (info, gdbarch);
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					 svr4_lp64_fetch_link_map_offsets);
+					 linux_lp64_fetch_link_map_offsets);
   set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_S390X);
 }
 
diff -Naur gdb-11.2.orig/gdb/sh-linux-tdep.c gdb-11.2/gdb/sh-linux-tdep.c
--- gdb-11.2.orig/gdb/sh-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/sh-linux-tdep.c	2022-02-06 14:36:56.659215682 -0600
@@ -189,7 +189,7 @@
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
   set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
 
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
diff -Naur gdb-11.2.orig/gdb/sparc64-linux-tdep.c gdb-11.2/gdb/sparc64-linux-tdep.c
--- gdb-11.2.orig/gdb/sparc64-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/sparc64-linux-tdep.c	2022-02-06 14:36:56.659215682 -0600
@@ -383,7 +383,7 @@
   /* GNU/Linux has SVR4-style shared libraries...  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_lp64_fetch_link_map_offsets);
+    (gdbarch, linux_lp64_fetch_link_map_offsets);
 
   /* ...which means that we need some special handling when doing
      prologue analysis.  */
diff -Naur gdb-11.2.orig/gdb/sparc-linux-tdep.c gdb-11.2/gdb/sparc-linux-tdep.c
--- gdb-11.2.orig/gdb/sparc-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/sparc-linux-tdep.c	2022-02-06 14:36:56.659215682 -0600
@@ -436,7 +436,7 @@
   /* GNU/Linux has SVR4-style shared libraries...  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 
   /* ...which means that we need some special handling when doing
      prologue analysis.  */
diff -Naur gdb-11.2.orig/gdb/tilegx-linux-tdep.c gdb-11.2/gdb/tilegx-linux-tdep.c
--- gdb-11.2.orig/gdb/tilegx-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/tilegx-linux-tdep.c	2022-02-06 14:36:56.659215682 -0600
@@ -121,10 +121,10 @@
   /* GNU/Linux uses SVR4-style shared libraries.  */
   if (arch_size == 32)
     set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					   svr4_ilp32_fetch_link_map_offsets);
+					   linux_ilp32_fetch_link_map_offsets);
   else
     set_solib_svr4_fetch_link_map_offsets (gdbarch,
-					   svr4_lp64_fetch_link_map_offsets);
+					   linux_lp64_fetch_link_map_offsets);
 
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
diff -Naur gdb-11.2.orig/gdb/xtensa-linux-tdep.c gdb-11.2/gdb/xtensa-linux-tdep.c
--- gdb-11.2.orig/gdb/xtensa-linux-tdep.c	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdb/xtensa-linux-tdep.c	2022-02-06 14:36:56.659215682 -0600
@@ -113,7 +113,7 @@
   linux_init_abi (info, gdbarch, 0);
 
   set_solib_svr4_fetch_link_map_offsets
-    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+    (gdbarch, linux_ilp32_fetch_link_map_offsets);
 
   set_gdbarch_gdb_signal_from_target (gdbarch,
 				      xtensa_linux_gdb_signal_from_target);
diff -Naur gdb-11.2.orig/gdbserver/linux-low.cc gdb-11.2/gdbserver/linux-low.cc
--- gdb-11.2.orig/gdbserver/linux-low.cc	2022-01-16 05:21:18.000000000 -0600
+++ gdb-11.2/gdbserver/linux-low.cc	2022-02-06 14:37:11.375345975 -0600
@@ -6845,7 +6845,7 @@
 	  if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
 				 (unsigned char *) &r_version,
 				 sizeof (r_version)) != 0
-	      || r_version != 1)
+	      || r_version < 1)
 	    {
 	      warning ("unexpected r_debug version %d", r_version);
 	    }
