[PATCH] Implement IP_STAT on NetBSD
Simon Marchi
simark@simark.ca
Mon Apr 13 19:16:12 GMT 2020
On 2020-04-13 2:19 p.m., Kamil Rytarowski wrote:
> NetBSD ships with a compatibility layer in a /proc virtual file system
> and delivers optionally /proc/<pid>/stat. In case of missing
> /proc/<pid>/stat fallback to emulating it with sysctl(3) APIs.
>
> gdb/ChangeLog:
>
> * nbsd-nat.c: Include "sys/resource.h" and "machine/vmparam.h".
> (nbsd_pid_to_kinfo_proc2, nbsd_pid_to_rlimit_cur)
> (nbsd_pid_to_statstr): New.
> (nbsd_nat_target::info_proc): Add do_stat.
> ---
> gdb/ChangeLog | 7 ++
> gdb/nbsd-nat.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 285 insertions(+)
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 7d91abf6334..5ff76e85cb3 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,10 @@
> +2020-04-13 Kamil Rytarowski <n54@gmx.com>
> +
> + * nbsd-nat.c: Include "sys/resource.h" and "machine/vmparam.h".
> + (nbsd_pid_to_kinfo_proc2, nbsd_pid_to_rlimit_cur)
> + (nbsd_pid_to_statstr): New.
> + (nbsd_nat_target::info_proc): Add do_stat.
> +
> 2020-04-12 Kamil Rytarowski <n54@gmx.com>
>
> * nbsd-nat.c (nbsd_nat_target::info_proc): Add IP_MINIMAL and
> diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c
> index 5eaf9dec8af..b2a05d63122 100644
> --- a/gdb/nbsd-nat.c
> +++ b/gdb/nbsd-nat.c
> @@ -28,6 +28,8 @@
> #include <sys/types.h>
> #include <sys/ptrace.h>
> #include <sys/sysctl.h>
> +#include <sys/resource.h>
> +#include <machine/vmparam.h>
>
> /* Return the name of a file that can be opened to get the symbols for
> the child process identified by PID. */
> @@ -58,6 +60,134 @@ nbsd_pid_to_cwd (int pid)
> return buf;
> }
>
> +/* Return the kinfo_proc2 structure for the process identified by PID. */
> +
> +static bool
> +nbsd_pid_to_kinfo_proc2(pid_t pid, struct kinfo_proc2 *ki)
Space.
> +{
> + gdb_assert (ki != nullptr);
> +
> + size_t size = sizeof (*ki);
> + int mib[6] = {CTL_KERN, KERN_PROC2, KERN_PROC_PID, pid,
> + static_cast<int> (size), 1};
> + return sysctl (mib, ARRAY_SIZE (mib), ki, &size, NULL, 0);
That looks counter-intuitive. sysctl returns 0 on success, which translates to
false as a bool. WHen a function returns a bool it is more typical that true
means success. This happens lower too.
> +}
> +
> +/* Return the RLIMIT value for the process identified by PID. */
> +
> +static bool
> +nbsd_pid_to_rlimit_cur(pid_t pid, rlim_t *rlim, int type)
Space.
> +{
> + gdb_assert (rlim != nullptr);
> +
> + size_t size = sizeof (*rlim);
> + int mib[5] = {CTL_PROC, pid, PROC_PID_LIMIT, type, PROC_PID_LIMIT_TYPE_SOFT};
> + return sysctl (mib, ARRAY_SIZE (mib), rlim, &size, NULL, 0);
> +}
> +
> +/* Return the emulated /proc/#/stat string for the process identified by PID.
> + NetBSD keeps the /proc filesystem that is optional and not recommended for
> + new software, thus this call emulates it with sysctl(3). */
> +
> +static gdb::unique_xmalloc_ptr<char>
> +nbsd_pid_to_statstr (int pid)
> +{
> + struct kinfo_proc2 ki;
> + if (nbsd_pid_to_kinfo_proc2 (pid, &ki))
> + return nullptr;
> +
> + struct rusage cru = {};
> + /* We can check only the current process. */
> + if (getpid() == pid)
Space.
> @@ -433,6 +568,149 @@ nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
> else
> warning (_("unable to fetch virtual memory map"));
> }
> + if (do_stat)
> + {
> + /* First, try with Linux-compat /proc/<pid>/stat. */
> + char filename[100];
> + xsnprintf (filename, sizeof filename, "/proc/%d/stat", pid);
Use
std::string filename = string_printf (...);
> + gdb::unique_xmalloc_ptr<char> statstr
> + = target_fileio_read_stralloc (NULL, filename);
> +
> + /* Then fallback to emulating /proc/<pid>/stat with sysctl(3). */
> + if (statstr == nullptr)
> + statstr = nbsd_pid_to_statstr (pid);
I find it a bit strange to take the route of formatting the contents of kinfo_proc2,
only to parse it here. I think it would have been more natural to do:
- If /proc/#/stat is available: string -> struct some_internal_struct -> print function
- If /proc/#/stat is available: kinfo_proc2 -> struct some_internal_struct -> print function
> +
> + if (statstr)
!= nullptr
> + {
> + 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". */
Either figure out how to print this correctly, or let's just leave it out.
Simon
More information about the Gdb-patches
mailing list