Implement "info proc mappings" for NetBSD
[deliverable/binutils-gdb.git] / gdb / nbsd-nat.c
CommitLineData
84c5b489
MK
1/* Native-dependent code for NetBSD.
2
b811d2c2 3 Copyright (C) 2006-2020 Free Software Foundation, Inc.
84c5b489
MK
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
84c5b489
MK
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
84c5b489
MK
19
20#include "defs.h"
21
84c5b489 22#include "nbsd-nat.h"
05f00e22 23#include "gdbthread.h"
54b8cbd0 24#include "nbsd-tdep.h"
05f00e22 25#include "inferior.h"
54b8cbd0 26#include "gdbarch.h"
84c5b489 27
a2ecbe9f
KR
28#include <sys/types.h>
29#include <sys/ptrace.h>
30#include <sys/sysctl.h>
31
766062f6 32/* Return the name of a file that can be opened to get the symbols for
84c5b489
MK
33 the child process identified by PID. */
34
35char *
f6ac5f3d 36nbsd_nat_target::pid_to_exec_file (int pid)
84c5b489 37{
b4ab256d 38 static char buf[PATH_MAX];
a2ecbe9f
KR
39 size_t buflen;
40 int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_PATHNAME};
41 buflen = sizeof (buf);
42 if (sysctl (mib, ARRAY_SIZE (mib), buf, &buflen, NULL, 0))
43 return NULL;
44 return buf;
84c5b489 45}
05f00e22
KR
46
47/* Generic thread (LWP) lister within a specified process. The callback
48 parameters is a C++ function that is called for each detected thread. */
49
50static bool
51nbsd_thread_lister (const pid_t pid,
52 gdb::function_view<bool (const struct kinfo_lwp *)>
53 callback)
54{
55 int mib[5] = {CTL_KERN, KERN_LWP, pid, sizeof (struct kinfo_lwp), 0};
56 size_t size;
57
58 if (sysctl (mib, ARRAY_SIZE (mib), NULL, &size, NULL, 0) == -1 || size == 0)
59 perror_with_name (("sysctl"));
60
61 mib[4] = size / sizeof (size_t);
62
63 gdb::unique_xmalloc_ptr<struct kinfo_lwp[]> kl
64 ((struct kinfo_lwp *) xcalloc (size, 1));
65
66 if (sysctl (mib, ARRAY_SIZE (mib), kl.get (), &size, NULL, 0) == -1
67 || size == 0)
68 perror_with_name (("sysctl"));
69
70 for (size_t i = 0; i < size / sizeof (struct kinfo_lwp); i++)
71 {
72 struct kinfo_lwp *l = &kl[i];
73
74 /* Return true if the specified thread is alive. */
75 auto lwp_alive
76 = [] (struct kinfo_lwp *lwp)
77 {
78 switch (lwp->l_stat)
79 {
80 case LSSLEEP:
81 case LSRUN:
82 case LSONPROC:
83 case LSSTOP:
84 case LSSUSPENDED:
85 return true;
86 default:
87 return false;
88 }
89 };
90
91 /* Ignore embryonic or demised threads. */
92 if (!lwp_alive (l))
93 continue;
94
95 if (callback (l))
96 return true;
97 }
98
99 return false;
100}
101
102/* Return true if PTID is still active in the inferior. */
103
104bool
105nbsd_nat_target::thread_alive (ptid_t ptid)
106{
107 pid_t pid = ptid.pid ();
108 int lwp = ptid.lwp ();
109
110 auto fn
111 = [&lwp] (const struct kinfo_lwp *kl)
112 {
113 return kl->l_lid == lwp;
114 };
115
116 return nbsd_thread_lister (pid, fn);
117}
118
119/* Return the name assigned to a thread by an application. Returns
120 the string in a static buffer. */
121
122const char *
123nbsd_nat_target::thread_name (struct thread_info *thr)
124{
125 ptid_t ptid = thr->ptid;
126 pid_t pid = ptid.pid ();
127 int lwp = ptid.lwp ();
128
129 static char buf[KI_LNAMELEN] = {};
130
131 auto fn
132 = [&lwp] (const struct kinfo_lwp *kl)
133 {
134 if (kl->l_lid == lwp)
135 {
136 xsnprintf (buf, sizeof buf, "%s", kl->l_name);
137 return true;
138 }
139 return false;
140 };
141
142 if (nbsd_thread_lister (pid, fn))
143 return buf;
144 else
145 return NULL;
146}
147
148/* Implement the "post_attach" target_ops method. */
149
150static void
151nbsd_add_threads (nbsd_nat_target *target, pid_t pid)
152{
153 auto fn
154 = [&target, &pid] (const struct kinfo_lwp *kl)
155 {
156 ptid_t ptid = ptid_t (pid, kl->l_lid, 0);
157 if (!in_thread_list (target, ptid))
158 {
159 if (inferior_ptid.lwp () == 0)
160 thread_change_ptid (target, inferior_ptid, ptid);
161 else
162 add_thread (target, ptid);
163 }
164 return false;
165 };
166
167 nbsd_thread_lister (pid, fn);
168}
169
170/* Implement the "post_attach" target_ops method. */
171
172void
173nbsd_nat_target::post_attach (int pid)
174{
175 nbsd_add_threads (this, pid);
176}
177
178/* Implement the "update_thread_list" target_ops method. */
179
180void
181nbsd_nat_target::update_thread_list ()
182{
183 prune_threads ();
184
185 nbsd_add_threads (this, inferior_ptid.pid ());
186}
187
188/* Convert PTID to a string. */
189
190std::string
191nbsd_nat_target::pid_to_str (ptid_t ptid)
192{
193 int lwp = ptid.lwp ();
194
195 if (lwp != 0)
196 {
197 pid_t pid = ptid.pid ();
198
199 return string_printf ("LWP %d of process %d", lwp, pid);
200 }
201
202 return normal_pid_to_str (ptid);
203}
54b8cbd0
KR
204
205/* Retrieve all the memory regions in the specified process. */
206
207static gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]>
208nbsd_kinfo_get_vmmap (pid_t pid, size_t *size)
209{
210 int mib[5] = {CTL_VM, VM_PROC, VM_PROC_MAP, pid,
211 sizeof (struct kinfo_vmentry)};
212
213 size_t length = 0;
214 if (sysctl (mib, ARRAY_SIZE (mib), NULL, &length, NULL, 0))
215 {
216 *size = 0;
217 return NULL;
218 }
219
220 /* Prereserve more space. The length argument is volatile and can change
221 between the sysctl(3) calls as this function can be called against a
222 running process. */
223 length = length * 5 / 3;
224
225 gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
226 (XNEWVAR (kinfo_vmentry, length));
227
228 if (sysctl (mib, ARRAY_SIZE (mib), kiv.get (), &length, NULL, 0))
229 {
230 *size = 0;
231 return NULL;
232 }
233
234 *size = length / sizeof (struct kinfo_vmentry);
235 return kiv;
236}
237
238/* Iterate over all the memory regions in the current inferior,
239 calling FUNC for each memory region. OBFD is passed as the last
240 argument to FUNC. */
241
242int
243nbsd_nat_target::find_memory_regions (find_memory_region_ftype func,
244 void *data)
245{
246 pid_t pid = inferior_ptid.pid ();
247
248 size_t nitems;
249 gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl
250 = nbsd_kinfo_get_vmmap (pid, &nitems);
251 if (vmentl == NULL)
252 perror_with_name (_("Couldn't fetch VM map entries."));
253
254 for (size_t i = 0; i < nitems; i++)
255 {
256 struct kinfo_vmentry *kve = &vmentl[i];
257
258 /* Skip unreadable segments and those where MAP_NOCORE has been set. */
259 if (!(kve->kve_protection & KVME_PROT_READ)
260 || kve->kve_flags & KVME_FLAG_NOCOREDUMP)
261 continue;
262
263 /* Skip segments with an invalid type. */
264 switch (kve->kve_type)
265 {
266 case KVME_TYPE_VNODE:
267 case KVME_TYPE_ANON:
268 case KVME_TYPE_SUBMAP:
269 case KVME_TYPE_OBJECT:
270 break;
271 default:
272 continue;
273 }
274
275 size_t size = kve->kve_end - kve->kve_start;
276 if (info_verbose)
277 {
278 fprintf_filtered (gdb_stdout,
279 "Save segment, %ld bytes at %s (%c%c%c)\n",
280 (long) size,
281 paddress (target_gdbarch (), kve->kve_start),
282 kve->kve_protection & KVME_PROT_READ ? 'r' : '-',
283 kve->kve_protection & KVME_PROT_WRITE ? 'w' : '-',
284 kve->kve_protection & KVME_PROT_EXEC ? 'x' : '-');
285 }
286
287 /* Invoke the callback function to create the corefile segment.
288 Pass MODIFIED as true, we do not know the real modification state. */
289 func (kve->kve_start, size, kve->kve_protection & KVME_PROT_READ,
290 kve->kve_protection & KVME_PROT_WRITE,
291 kve->kve_protection & KVME_PROT_EXEC, 1, data);
292 }
293 return 0;
294}
295
296/* Implement the "info_proc" target_ops method. */
297
298bool
299nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
300{
301 pid_t pid;
302 bool do_mappings = false;
303
304 switch (what)
305 {
306 case IP_MAPPINGS:
307 do_mappings = true;
308 break;
309 default:
310 error (_("Not supported on this target."));
311 }
312
313 gdb_argv built_argv (args);
314 if (built_argv.count () == 0)
315 {
316 pid = inferior_ptid.pid ();
317 if (pid == 0)
318 error (_("No current process: you must name one."));
319 }
320 else if (built_argv.count () == 1 && isdigit (built_argv[0][0]))
321 pid = strtol (built_argv[0], NULL, 10);
322 else
323 error (_("Invalid arguments."));
324
325 printf_filtered (_("process %d\n"), pid);
326
327 if (do_mappings)
328 {
329 size_t nvment;
330 gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl
331 = nbsd_kinfo_get_vmmap (pid, &nvment);
332
333 if (vmentl != nullptr)
334 {
335 int addr_bit = TARGET_CHAR_BIT * sizeof (void *);
336 nbsd_info_proc_mappings_header (addr_bit);
337
338 struct kinfo_vmentry *kve = vmentl.get ();
339 for (int i = 0; i < nvment; i++, kve++)
340 nbsd_info_proc_mappings_entry (addr_bit, kve->kve_start,
341 kve->kve_end, kve->kve_offset,
342 kve->kve_flags, kve->kve_protection,
343 kve->kve_path);
344 }
345 else
346 warning (_("unable to fetch virtual memory map"));
347 }
348
349 return true;
350}
This page took 1.226441 seconds and 4 git commands to generate.