[v3] Implement "info proc mappings" for NetBSD

Message ID 20200406093753.13772-1-n54@gmx.com
State Superseded
Headers show
Series
  • [v3] Implement "info proc mappings" for NetBSD
Related show

Commit Message

Kamil Rytarowski April 6, 2020, 9:37 a.m.
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", "inferior.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  | 148 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/nbsd-nat.h  |   2 +
 gdb/nbsd-tdep.c |  91 +++++++++++++++++++++++++++++
 gdb/nbsd-tdep.h |  18 ++++++
 5 files changed, 276 insertions(+)

--
2.25.0

Comments

Kamil Rytarowski April 10, 2020, 10:20 a.m. | #1
Ping?

On 06.04.2020 11:37, Kamil Rytarowski wrote:
> 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", "inferior.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  | 148 ++++++++++++++++++++++++++++++++++++++++++++++++

>  gdb/nbsd-nat.h  |   2 +

>  gdb/nbsd-tdep.c |  91 +++++++++++++++++++++++++++++

>  gdb/nbsd-tdep.h |  18 ++++++

>  5 files changed, 276 insertions(+)

>

> diff --git a/gdb/ChangeLog b/gdb/ChangeLog

> index 650b74bae4a..b12965e41bb 100644

> --- a/gdb/ChangeLog

> +++ b/gdb/ChangeLog

> @@ -1,3 +1,20 @@

> +2020-03-20  Kamil Rytarowski  <n54@gmx.com>

> +

> +	* nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-20  Kamil Rytarowski  <n54@gmx.com>

>

>  	* amd64-bsd-nat.c (gdb_ptrace): Change return type from `int' to

> diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c

> index 326bbe3aec3..82f9837b775 100644

> --- a/gdb/nbsd-nat.c

> +++ b/gdb/nbsd-nat.c

> @@ -20,6 +20,9 @@

>  #include "defs.h"

>

>  #include "nbsd-nat.h"

> +#include "nbsd-tdep.h"

> +#include "inferior.h"

> +#include "gdbarch.h"

>

>  #include <sys/types.h>

>  #include <sys/ptrace.h>

> @@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)

>      return NULL;

>    return buf;

>  }

> +

> +/* 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. */

> +  length = length * 5 / 3;

> +

> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv

> +    ((struct kinfo_vmentry *) xcalloc (length, 1));

> +

> +  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;

> +}

> diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h

> index a752fbe572d..98af21d0bda 100644

> --- a/gdb/nbsd-nat.h

> +++ b/gdb/nbsd-nat.h

> @@ -27,6 +27,8 @@

>  struct nbsd_nat_target : public inf_ptrace_target

>  {

>    char *pid_to_exec_file (int pid) 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 49bb2b706bd..29dc9172306 100644

> --- a/gdb/nbsd-tdep.c

> +++ b/gdb/nbsd-tdep.c

> @@ -23,6 +23,23 @@

>  #include "solib-svr4.h"

>  #include "nbsd-tdep.h"

>

> +/* Flags in the 'kve_protection' field in struct kinfo_vmentry.  These

> +   match the KVME_PROT_* constants in <sys/sysctl.h>.  */

> +

> +#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 <sys/sysctl.h>.  */

> +

> +#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.  */

>

> @@ -47,3 +64,77 @@ nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)

>    return (func_name != NULL

>  	  && startswith (func_name, "__sigtramp"));

>  }

> +

> +/* 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;

> +}

> +

> +/* See nbsd-tdep.h.  */

> +

> +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 void *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),

> +		       reinterpret_cast<const char *> (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),

> +		       reinterpret_cast<const char *> (kve_path));

> +    }

> +}

> diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h

> index c99a8b537b6..81bdb2510f5 100644

> --- a/gdb/nbsd-tdep.h

> +++ b/gdb/nbsd-tdep.h

> @@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

>

>  int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

>

> +/* 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 void *kve_path);

> +

>  #endif /* NBSD_TDEP_H */

> --

> 2.25.0

>
Simon Marchi April 11, 2020, 9:05 p.m. | #2
On 2020-04-06 5:37 a.m., Kamil Rytarowski wrote:
> @@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)

>      return NULL;

>    return buf;

>  }

> +

> +/* 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. */

> +  length = length * 5 / 3;


Why is this needed?

> +

> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv

> +    ((struct kinfo_vmentry *) xcalloc (length, 1));


Let's use XCNEWVAR here.  It doesn't matter in this case, but for consistency.  It does
check that we are not trying to allocate space for a non-POD type.  You can use like:

  XCNEWVAR (kinfo_vmentry, length)

You can also use XNEWVAR if you don't care about the buffer being initialized to zeros.

> diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h

> index c99a8b537b6..81bdb2510f5 100644

> --- a/gdb/nbsd-tdep.h

> +++ b/gdb/nbsd-tdep.h

> @@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

> 

>  int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

> 

> +/* 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 void *kve_path);


I'd make the last parameter a `const char *` directly, since this is what the function
expects to receive.  And remove the reinterpret_casts.

Simon
Kamil Rytarowski April 11, 2020, 9:28 p.m. | #3
On 11.04.2020 23:05, Simon Marchi wrote:
> On 2020-04-06 5:37 a.m., Kamil Rytarowski wrote:

>> @@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)

>>      return NULL;

>>    return buf;

>>  }

>> +

>> +/* 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. */

>> +  length = length * 5 / 3;

>

> Why is this needed?

>


This length is volatile and can be larger on the 2nd sysctl(3) call. We
can call this function against a running process that can enlarge its
usage of address space in this time window.

>> +

>> +  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv

>> +    ((struct kinfo_vmentry *) xcalloc (length, 1));

>

> Let's use XCNEWVAR here.  It doesn't matter in this case, but for consistency.  It does

> check that we are not trying to allocate space for a non-POD type.  You can use like:

>

>   XCNEWVAR (kinfo_vmentry, length)

>

> You can also use XNEWVAR if you don't care about the buffer being initialized to zeros.

>


OK.

>> diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h

>> index c99a8b537b6..81bdb2510f5 100644

>> --- a/gdb/nbsd-tdep.h

>> +++ b/gdb/nbsd-tdep.h

>> @@ -25,4 +25,22 @@ struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

>>

>>  int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

>>

>> +/* 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 void *kve_path);

>

> I'd make the last parameter a `const char *` directly, since this is what the function

> expects to receive.  And remove the reinterpret_casts.

>


OK.

> Simon

>
Simon Marchi April 11, 2020, 9:53 p.m. | #4
On 2020-04-11 5:28 p.m., Kamil Rytarowski wrote:
> On 11.04.2020 23:05, Simon Marchi wrote:

>> On 2020-04-06 5:37 a.m., Kamil Rytarowski wrote:

>>> @@ -39,3 +42,148 @@ nbsd_nat_target::pid_to_exec_file (int pid)

>>>      return NULL;

>>>    return buf;

>>>  }

>>> +

>>> +/* 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. */

>>> +  length = length * 5 / 3;

>>

>> Why is this needed?

>>

> 

> This length is volatile and can be larger on the 2nd sysctl(3) call. We

> can call this function against a running process that can enlarge its

> usage of address space in this time window.


Ok, then please make the comment explain that.  We can see that the expression
increases length, but as a reader I have no idea why.

Simon

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 650b74bae4a..b12965e41bb 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,20 @@ 
+2020-03-20  Kamil Rytarowski  <n54@gmx.com>
+
+	* nbsd-nat.c; Include "nbsd-tdep.h", "inferior.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-03-20  Kamil Rytarowski  <n54@gmx.com>

 	* amd64-bsd-nat.c (gdb_ptrace): Change return type from `int' to
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
index 326bbe3aec3..82f9837b775 100644
--- a/gdb/nbsd-nat.c
+++ b/gdb/nbsd-nat.c
@@ -20,6 +20,9 @@ 
 #include "defs.h"

 #include "nbsd-nat.h"
+#include "nbsd-tdep.h"
+#include "inferior.h"
+#include "gdbarch.h"

 #include <sys/types.h>
 #include <sys/ptrace.h>
@@ -39,3 +42,148 @@  nbsd_nat_target::pid_to_exec_file (int pid)
     return NULL;
   return buf;
 }
+
+/* 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. */
+  length = length * 5 / 3;
+
+  gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
+    ((struct kinfo_vmentry *) xcalloc (length, 1));
+
+  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;
+}
diff --git a/gdb/nbsd-nat.h b/gdb/nbsd-nat.h
index a752fbe572d..98af21d0bda 100644
--- a/gdb/nbsd-nat.h
+++ b/gdb/nbsd-nat.h
@@ -27,6 +27,8 @@ 
 struct nbsd_nat_target : public inf_ptrace_target
 {
   char *pid_to_exec_file (int pid) 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 49bb2b706bd..29dc9172306 100644
--- a/gdb/nbsd-tdep.c
+++ b/gdb/nbsd-tdep.c
@@ -23,6 +23,23 @@ 
 #include "solib-svr4.h"
 #include "nbsd-tdep.h"

+/* Flags in the 'kve_protection' field in struct kinfo_vmentry.  These
+   match the KVME_PROT_* constants in <sys/sysctl.h>.  */
+
+#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 <sys/sysctl.h>.  */
+
+#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.  */

@@ -47,3 +64,77 @@  nbsd_pc_in_sigtramp (CORE_ADDR pc, const char *func_name)
   return (func_name != NULL
 	  && startswith (func_name, "__sigtramp"));
 }
+
+/* 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;
+}
+
+/* See nbsd-tdep.h.  */
+
+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 void *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),
+		       reinterpret_cast<const char *> (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),
+		       reinterpret_cast<const char *> (kve_path));
+    }
+}
diff --git a/gdb/nbsd-tdep.h b/gdb/nbsd-tdep.h
index c99a8b537b6..81bdb2510f5 100644
--- a/gdb/nbsd-tdep.h
+++ b/gdb/nbsd-tdep.h
@@ -25,4 +25,22 @@  struct link_map_offsets *nbsd_lp64_solib_svr4_fetch_link_map_offsets (void);

 int nbsd_pc_in_sigtramp (CORE_ADDR, const char *);

+/* 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 void *kve_path);
+
 #endif /* NBSD_TDEP_H */