Submitted By: Bruce Dubbs 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 @@ -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 . */ + +#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 + +/* 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//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//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 , 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 + , 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 + , 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 (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 disp_step_bufs; +}; + +/* Per-inferior data key. */ +static const struct inferior_key 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 + , 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 ' (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 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 + . */ + 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 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 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 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 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 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 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 + pre_loop_cb, + gdb::function_view + 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 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//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 +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 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 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 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 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 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 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 ¬e_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 ¬e_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 ¬e_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 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 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 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 +linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size) +{ + struct elf_internal_linux_prpsinfo prpsinfo; + gdb::unique_xmalloc_ptr 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 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, ¬e_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 , + 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 , + 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 + 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 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 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, µmips_linux_o32_sigframe); tramp_frame_prepend_unwinder (gdbarch, µmips_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 . */ + +#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); }