From 54b8cbd0e4063846349634aefa8ed1a3c0ac62ca Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sun, 12 Apr 2020 02:00:14 +0200 Subject: [PATCH] Implement "info proc mappings" for NetBSD Define nbsd_nat_target::find_memory_regions and nbsd_nat_target::info_proc. info_proc handles as of now only the "mappings" command. Define a local static function kinfo_get_vmmap() that reads the process memory layout of a specified process. kinfo_get_vmmap() wraps the sysctl(3) call. nbsd-tdep.c defines now utility functions for printing the process memory layout: * nbsd_info_proc_mappings_header() * nbsd_vm_map_entry_flags() * nbsd_info_proc_mappings_entry() gdb/ChangeLog: * nbsd-nat.c; Include "nbsd-tdep.h" and "gdbarch.h". * nbsd-nat.c (nbsd_nat_target::find_memory_regions) (nbsd_nat_target::info_proc): New functions. * nbsd-nat.c (kinfo_get_vmmap): New function. * nbsd-nat.c (nbsd_nat_target::info_proc) Use nbsd_info_proc_mappings_header and nbsd_info_proc_mappings_entry. * nbsd-tdep.c (nbsd_info_proc_mappings_header) (nbsd_info_proc_mappings_entry, nbsd_vm_map_entry_flags): New functions. * nbsd-tdep.c (KINFO_VME_PROT_READ, KINFO_VME_PROT_WRITE) (KINFO_VME_PROT_EXEC, KINFO_VME_FLAG_COW) (KINFO_VME_FLAG_NEEDS_COPY, KINFO_VME_FLAG_NOCOREDUMP) (KINFO_VME_FLAG_PAGEABLE, KINFO_VME_FLAG_GROWS_UP) (KINFO_VME_FLAG_GROWS_DOWN): New. --- gdb/ChangeLog | 17 ++++++ gdb/nbsd-nat.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ gdb/nbsd-nat.h | 3 + gdb/nbsd-tdep.c | 89 +++++++++++++++++++++++++++++ gdb/nbsd-tdep.h | 18 ++++++ 5 files changed, 276 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 81102ee569..336bd49741 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,20 @@ +2020-04-11 Kamil Rytarowski + + * nbsd-nat.c; Include "nbsd-tdep.h" and "gdbarch.h". + * nbsd-nat.c (nbsd_nat_target::find_memory_regions) + (nbsd_nat_target::info_proc): New functions. + * nbsd-nat.c (kinfo_get_vmmap): New function. + * nbsd-nat.c (nbsd_nat_target::info_proc) Use + nbsd_info_proc_mappings_header and nbsd_info_proc_mappings_entry. + * nbsd-tdep.c (nbsd_info_proc_mappings_header) + (nbsd_info_proc_mappings_entry, nbsd_vm_map_entry_flags): New + functions. + * nbsd-tdep.c (KINFO_VME_PROT_READ, KINFO_VME_PROT_WRITE) + (KINFO_VME_PROT_EXEC, KINFO_VME_FLAG_COW) + (KINFO_VME_FLAG_NEEDS_COPY, KINFO_VME_FLAG_NOCOREDUMP) + (KINFO_VME_FLAG_PAGEABLE, KINFO_VME_FLAG_GROWS_UP) + (KINFO_VME_FLAG_GROWS_DOWN): New. + 2020-04-10 Artur Shepilko * utils.c (copy_bitwise): Use unsigned 0 constant as operand of diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c index 4423e19428..2420153c7b 100644 --- a/gdb/nbsd-nat.c +++ b/gdb/nbsd-nat.c @@ -21,7 +21,9 @@ #include "nbsd-nat.h" #include "gdbthread.h" +#include "nbsd-tdep.h" #include "inferior.h" +#include "gdbarch.h" #include #include @@ -199,3 +201,150 @@ nbsd_nat_target::pid_to_str (ptid_t ptid) return normal_pid_to_str (ptid); } + +/* Retrieve all the memory regions in the specified process. */ + +static gdb::unique_xmalloc_ptr +nbsd_kinfo_get_vmmap (pid_t pid, size_t *size) +{ + int mib[5] = {CTL_VM, VM_PROC, VM_PROC_MAP, pid, + sizeof (struct kinfo_vmentry)}; + + size_t length = 0; + if (sysctl (mib, ARRAY_SIZE (mib), NULL, &length, NULL, 0)) + { + *size = 0; + return NULL; + } + + /* Prereserve more space. The length argument is volatile and can change + between the sysctl(3) calls as this function can be called against a + running process. */ + length = length * 5 / 3; + + gdb::unique_xmalloc_ptr kiv + (XNEWVAR (kinfo_vmentry, length)); + + if (sysctl (mib, ARRAY_SIZE (mib), kiv.get (), &length, NULL, 0)) + { + *size = 0; + return NULL; + } + + *size = length / sizeof (struct kinfo_vmentry); + return kiv; +} + +/* Iterate over all the memory regions in the current inferior, + calling FUNC for each memory region. OBFD is passed as the last + argument to FUNC. */ + +int +nbsd_nat_target::find_memory_regions (find_memory_region_ftype func, + void *data) +{ + pid_t pid = inferior_ptid.pid (); + + size_t nitems; + gdb::unique_xmalloc_ptr vmentl + = nbsd_kinfo_get_vmmap (pid, &nitems); + if (vmentl == NULL) + perror_with_name (_("Couldn't fetch VM map entries.")); + + for (size_t i = 0; i < nitems; i++) + { + struct kinfo_vmentry *kve = &vmentl[i]; + + /* Skip unreadable segments and those where MAP_NOCORE has been set. */ + if (!(kve->kve_protection & KVME_PROT_READ) + || kve->kve_flags & KVME_FLAG_NOCOREDUMP) + continue; + + /* Skip segments with an invalid type. */ + switch (kve->kve_type) + { + case KVME_TYPE_VNODE: + case KVME_TYPE_ANON: + case KVME_TYPE_SUBMAP: + case KVME_TYPE_OBJECT: + break; + default: + continue; + } + + size_t size = kve->kve_end - kve->kve_start; + if (info_verbose) + { + fprintf_filtered (gdb_stdout, + "Save segment, %ld bytes at %s (%c%c%c)\n", + (long) size, + paddress (target_gdbarch (), kve->kve_start), + kve->kve_protection & KVME_PROT_READ ? 'r' : '-', + kve->kve_protection & KVME_PROT_WRITE ? 'w' : '-', + kve->kve_protection & KVME_PROT_EXEC ? 'x' : '-'); + } + + /* Invoke the callback function to create the corefile segment. + Pass MODIFIED as true, we do not know the real modification state. */ + func (kve->kve_start, size, kve->kve_protection & KVME_PROT_READ, + kve->kve_protection & KVME_PROT_WRITE, + kve->kve_protection & KVME_PROT_EXEC, 1, data); + } + return 0; +} + +/* Implement the "info_proc" target_ops method. */ + +bool +nbsd_nat_target::info_proc (const char *args, enum info_proc_what what) +{ + pid_t pid; + bool do_mappings = false; + + switch (what) + { + case IP_MAPPINGS: + do_mappings = true; + break; + default: + error (_("Not supported on this target.")); + } + + gdb_argv built_argv (args); + if (built_argv.count () == 0) + { + pid = inferior_ptid.pid (); + if (pid == 0) + error (_("No current process: you must name one.")); + } + else if (built_argv.count () == 1 && isdigit (built_argv[0][0])) + pid = strtol (built_argv[0], NULL, 10); + else + error (_("Invalid arguments.")); + + printf_filtered (_("process %d\n"), pid); + + if (do_mappings) + { + size_t nvment; + gdb::unique_xmalloc_ptr vmentl + = nbsd_kinfo_get_vmmap (pid, &nvment); + + if (vmentl != nullptr) + { + int addr_bit = TARGET_CHAR_BIT * sizeof (void *); + nbsd_info_proc_mappings_header (addr_bit); + + struct kinfo_vmentry *kve = vmentl.get (); + for (int i = 0; i < nvment; i++, kve++) + nbsd_info_proc_mappings_entry (addr_bit, kve->kve_start, + kve->kve_end, kve->kve_offset, + kve->kve_flags, kve->kve_protection, + kve->kve_path); + } + else + warning (_("unable to fetch virtual memory map")); + } + + return true; +} diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h index 3606048cd0..256db4b901 100644 --- a/gdb/nbsd-nat.h +++ b/gdb/nbsd-nat.h @@ -35,6 +35,9 @@ struct nbsd_nat_target : public inf_ptrace_target void post_attach (int pid) override; void update_thread_list () override; std::string pid_to_str (ptid_t ptid) override; + + int find_memory_regions (find_memory_region_ftype func, void *data) override; + bool info_proc (const char *, enum info_proc_what) override; }; #endif /* nbsd-nat.h */ diff --git a/gdb/nbsd-tdep.c b/gdb/nbsd-tdep.c index 158a43beba..52e0640e35 100644 --- a/gdb/nbsd-tdep.c +++ b/gdb/nbsd-tdep.c @@ -26,6 +26,23 @@ #include "gdbarch.h" #include "objfiles.h" +/* Flags in the 'kve_protection' field in struct kinfo_vmentry. These + match the KVME_PROT_* constants in . */ + +#define KINFO_VME_PROT_READ 0x00000001 +#define KINFO_VME_PROT_WRITE 0x00000002 +#define KINFO_VME_PROT_EXEC 0x00000004 + +/* Flags in the 'kve_flags' field in struct kinfo_vmentry. These + match the KVME_FLAG_* constants in . */ + +#define KINFO_VME_FLAG_COW 0x00000001 +#define KINFO_VME_FLAG_NEEDS_COPY 0x00000002 +#define KINFO_VME_FLAG_NOCOREDUMP 0x00000004 +#define KINFO_VME_FLAG_PAGEABLE 0x00000008 +#define KINFO_VME_FLAG_GROWS_UP 0x00000010 +#define KINFO_VME_FLAG_GROWS_DOWN 0x00000020 + /* FIXME: kettenis/20060115: We should really eliminate the next two functions completely. */ @@ -357,6 +374,78 @@ nbsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) /* See nbsd-tdep.h. */ +void +nbsd_info_proc_mappings_header (int addr_bit) +{ + printf_filtered (_("Mapped address spaces:\n\n")); + if (addr_bit == 64) + { + printf_filtered (" %18s %18s %10s %10s %9s %s\n", + "Start Addr", + " End Addr", + " Size", " Offset", "Flags ", "File"); + } + else + { + printf_filtered ("\t%10s %10s %10s %10s %9s %s\n", + "Start Addr", + " End Addr", + " Size", " Offset", "Flags ", "File"); + } +} + +/* Helper function to generate mappings flags for a single VM map + entry in 'info proc mappings'. */ + +static const char * +nbsd_vm_map_entry_flags (int kve_flags, int kve_protection) +{ + static char vm_flags[9]; + + vm_flags[0] = (kve_protection & KINFO_VME_PROT_READ) ? 'r' : '-'; + vm_flags[1] = (kve_protection & KINFO_VME_PROT_WRITE) ? 'w' : '-'; + vm_flags[2] = (kve_protection & KINFO_VME_PROT_EXEC) ? 'x' : '-'; + vm_flags[3] = ' '; + vm_flags[4] = (kve_flags & KINFO_VME_FLAG_COW) ? 'C' : '-'; + vm_flags[5] = (kve_flags & KINFO_VME_FLAG_NEEDS_COPY) ? 'N' : '-'; + vm_flags[6] = (kve_flags & KINFO_VME_FLAG_PAGEABLE) ? 'P' : '-'; + vm_flags[7] = (kve_flags & KINFO_VME_FLAG_GROWS_UP) ? 'U' + : (kve_flags & KINFO_VME_FLAG_GROWS_DOWN) ? 'D' : '-'; + vm_flags[8] = '\0'; + + return vm_flags; +} + +void +nbsd_info_proc_mappings_entry (int addr_bit, ULONGEST kve_start, + ULONGEST kve_end, ULONGEST kve_offset, + int kve_flags, int kve_protection, + const char *kve_path) +{ + if (addr_bit == 64) + { + printf_filtered (" %18s %18s %10s %10s %9s %s\n", + hex_string (kve_start), + hex_string (kve_end), + hex_string (kve_end - kve_start), + hex_string (kve_offset), + nbsd_vm_map_entry_flags (kve_flags, kve_protection), + kve_path); + } + else + { + printf_filtered ("\t%10s %10s %10s %10s %9s %s\n", + hex_string (kve_start), + hex_string (kve_end), + hex_string (kve_end - kve_start), + hex_string (kve_offset), + nbsd_vm_map_entry_flags (kve_flags, kve_protection), + kve_path); + } +} + +/* See nbsd-tdep.h. */ + void nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h index 4b06c13f87..a6e3a8f0f3 100644 --- a/gdb/nbsd-tdep.h +++ b/gdb/nbsd-tdep.h @@ -29,4 +29,22 @@ int nbsd_pc_in_sigtramp (CORE_ADDR, const char *); void nbsd_init_abi (struct gdbarch_info, struct gdbarch *); +/* Output the header for "info proc mappings". ADDR_BIT is the size + of a virtual address in bits. */ + +extern void nbsd_info_proc_mappings_header (int addr_bit); + +/* Output description of a single memory range for "info proc + mappings". ADDR_BIT is the size of a virtual address in bits. The + KVE_START, KVE_END, KVE_OFFSET, KVE_FLAGS, and KVE_PROTECTION + parameters should contain the value of the corresponding fields in + a 'struct kinfo_vmentry'. The KVE_PATH parameter should contain a + pointer to the 'kve_path' field in a 'struct kinfo_vmentry'. */ + +extern void nbsd_info_proc_mappings_entry (int addr_bit, ULONGEST kve_start, + ULONGEST kve_end, + ULONGEST kve_offset, + int kve_flags, int kve_protection, + const char *kve_path); + #endif /* NBSD_TDEP_H */ -- 2.34.1