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.
This commit is contained in:
Kamil Rytarowski
2020-04-12 02:00:14 +02:00
parent 0b07a19901
commit 54b8cbd0e4
5 changed files with 276 additions and 0 deletions

View File

@ -21,7 +21,9 @@
#include "nbsd-nat.h"
#include "gdbthread.h"
#include "nbsd-tdep.h"
#include "inferior.h"
#include "gdbarch.h"
#include <sys/types.h>
#include <sys/ptrace.h>
@ -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<struct kinfo_vmentry[]>
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<struct kinfo_vmentry[]> 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<struct kinfo_vmentry[]> 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<struct kinfo_vmentry[]> 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;
}