Implement IP_MINIMAL and IP_ALL on 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 46
b4848d2a
KR
47/* Return the current directory for the process identified by PID. */
48
49static std::string
50nbsd_pid_to_cwd (int pid)
51{
52 char buf[PATH_MAX];
53 size_t buflen;
54 int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_CWD};
55 buflen = sizeof (buf);
56 if (sysctl (mib, ARRAY_SIZE (mib), buf, &buflen, NULL, 0))
57 return "";
58 return buf;
59}
60
49d1d1f5
KR
61/* Return the command line for the process identified by PID. */
62
63static gdb::unique_xmalloc_ptr<char[]>
64nbsd_pid_to_cmdline (int pid)
65{
66 int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
67
68 size_t size = 0;
69 if (sysctl (mib, ARRAY_SIZE (mib), NULL, &size, NULL, 0) == -1 || size == 0)
70 return nullptr;
71
72 gdb::unique_xmalloc_ptr<char[]> args (XNEWVAR (char, size));
73
74 if (sysctl (mib, ARRAY_SIZE (mib), args.get (), &size, NULL, 0) == -1
75 || size == 0)
76 return nullptr;
77
78 /* Arguments are returned as a flattened string with NUL separators.
79 Join the arguments with spaces to form a single string. */
80 for (size_t i = 0; i < size - 1; i++)
81 if (args[i] == '\0')
82 args[i] = ' ';
83 args[size - 1] = '\0';
84
85 return args;
86}
87
05f00e22
KR
88/* Generic thread (LWP) lister within a specified process. The callback
89 parameters is a C++ function that is called for each detected thread. */
90
91static bool
92nbsd_thread_lister (const pid_t pid,
93 gdb::function_view<bool (const struct kinfo_lwp *)>
94 callback)
95{
96 int mib[5] = {CTL_KERN, KERN_LWP, pid, sizeof (struct kinfo_lwp), 0};
97 size_t size;
98
99 if (sysctl (mib, ARRAY_SIZE (mib), NULL, &size, NULL, 0) == -1 || size == 0)
100 perror_with_name (("sysctl"));
101
102 mib[4] = size / sizeof (size_t);
103
104 gdb::unique_xmalloc_ptr<struct kinfo_lwp[]> kl
105 ((struct kinfo_lwp *) xcalloc (size, 1));
106
107 if (sysctl (mib, ARRAY_SIZE (mib), kl.get (), &size, NULL, 0) == -1
108 || size == 0)
109 perror_with_name (("sysctl"));
110
111 for (size_t i = 0; i < size / sizeof (struct kinfo_lwp); i++)
112 {
113 struct kinfo_lwp *l = &kl[i];
114
115 /* Return true if the specified thread is alive. */
116 auto lwp_alive
117 = [] (struct kinfo_lwp *lwp)
118 {
119 switch (lwp->l_stat)
120 {
121 case LSSLEEP:
122 case LSRUN:
123 case LSONPROC:
124 case LSSTOP:
125 case LSSUSPENDED:
126 return true;
127 default:
128 return false;
129 }
130 };
131
132 /* Ignore embryonic or demised threads. */
133 if (!lwp_alive (l))
134 continue;
135
136 if (callback (l))
137 return true;
138 }
139
140 return false;
141}
142
143/* Return true if PTID is still active in the inferior. */
144
145bool
146nbsd_nat_target::thread_alive (ptid_t ptid)
147{
148 pid_t pid = ptid.pid ();
149 int lwp = ptid.lwp ();
150
151 auto fn
152 = [&lwp] (const struct kinfo_lwp *kl)
153 {
154 return kl->l_lid == lwp;
155 };
156
157 return nbsd_thread_lister (pid, fn);
158}
159
160/* Return the name assigned to a thread by an application. Returns
161 the string in a static buffer. */
162
163const char *
164nbsd_nat_target::thread_name (struct thread_info *thr)
165{
166 ptid_t ptid = thr->ptid;
167 pid_t pid = ptid.pid ();
168 int lwp = ptid.lwp ();
169
170 static char buf[KI_LNAMELEN] = {};
171
172 auto fn
173 = [&lwp] (const struct kinfo_lwp *kl)
174 {
175 if (kl->l_lid == lwp)
176 {
177 xsnprintf (buf, sizeof buf, "%s", kl->l_name);
178 return true;
179 }
180 return false;
181 };
182
183 if (nbsd_thread_lister (pid, fn))
184 return buf;
185 else
186 return NULL;
187}
188
189/* Implement the "post_attach" target_ops method. */
190
191static void
192nbsd_add_threads (nbsd_nat_target *target, pid_t pid)
193{
194 auto fn
195 = [&target, &pid] (const struct kinfo_lwp *kl)
196 {
197 ptid_t ptid = ptid_t (pid, kl->l_lid, 0);
198 if (!in_thread_list (target, ptid))
199 {
200 if (inferior_ptid.lwp () == 0)
201 thread_change_ptid (target, inferior_ptid, ptid);
202 else
203 add_thread (target, ptid);
204 }
205 return false;
206 };
207
208 nbsd_thread_lister (pid, fn);
209}
210
211/* Implement the "post_attach" target_ops method. */
212
213void
214nbsd_nat_target::post_attach (int pid)
215{
216 nbsd_add_threads (this, pid);
217}
218
219/* Implement the "update_thread_list" target_ops method. */
220
221void
222nbsd_nat_target::update_thread_list ()
223{
224 prune_threads ();
225
226 nbsd_add_threads (this, inferior_ptid.pid ());
227}
228
229/* Convert PTID to a string. */
230
231std::string
232nbsd_nat_target::pid_to_str (ptid_t ptid)
233{
234 int lwp = ptid.lwp ();
235
236 if (lwp != 0)
237 {
238 pid_t pid = ptid.pid ();
239
240 return string_printf ("LWP %d of process %d", lwp, pid);
241 }
242
243 return normal_pid_to_str (ptid);
244}
54b8cbd0
KR
245
246/* Retrieve all the memory regions in the specified process. */
247
248static gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]>
249nbsd_kinfo_get_vmmap (pid_t pid, size_t *size)
250{
251 int mib[5] = {CTL_VM, VM_PROC, VM_PROC_MAP, pid,
252 sizeof (struct kinfo_vmentry)};
253
254 size_t length = 0;
255 if (sysctl (mib, ARRAY_SIZE (mib), NULL, &length, NULL, 0))
256 {
257 *size = 0;
258 return NULL;
259 }
260
261 /* Prereserve more space. The length argument is volatile and can change
262 between the sysctl(3) calls as this function can be called against a
263 running process. */
264 length = length * 5 / 3;
265
266 gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv
267 (XNEWVAR (kinfo_vmentry, length));
268
269 if (sysctl (mib, ARRAY_SIZE (mib), kiv.get (), &length, NULL, 0))
270 {
271 *size = 0;
272 return NULL;
273 }
274
275 *size = length / sizeof (struct kinfo_vmentry);
276 return kiv;
277}
278
279/* Iterate over all the memory regions in the current inferior,
280 calling FUNC for each memory region. OBFD is passed as the last
281 argument to FUNC. */
282
283int
284nbsd_nat_target::find_memory_regions (find_memory_region_ftype func,
285 void *data)
286{
287 pid_t pid = inferior_ptid.pid ();
288
289 size_t nitems;
290 gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl
291 = nbsd_kinfo_get_vmmap (pid, &nitems);
292 if (vmentl == NULL)
293 perror_with_name (_("Couldn't fetch VM map entries."));
294
295 for (size_t i = 0; i < nitems; i++)
296 {
297 struct kinfo_vmentry *kve = &vmentl[i];
298
299 /* Skip unreadable segments and those where MAP_NOCORE has been set. */
300 if (!(kve->kve_protection & KVME_PROT_READ)
301 || kve->kve_flags & KVME_FLAG_NOCOREDUMP)
302 continue;
303
304 /* Skip segments with an invalid type. */
305 switch (kve->kve_type)
306 {
307 case KVME_TYPE_VNODE:
308 case KVME_TYPE_ANON:
309 case KVME_TYPE_SUBMAP:
310 case KVME_TYPE_OBJECT:
311 break;
312 default:
313 continue;
314 }
315
316 size_t size = kve->kve_end - kve->kve_start;
317 if (info_verbose)
318 {
319 fprintf_filtered (gdb_stdout,
320 "Save segment, %ld bytes at %s (%c%c%c)\n",
321 (long) size,
322 paddress (target_gdbarch (), kve->kve_start),
323 kve->kve_protection & KVME_PROT_READ ? 'r' : '-',
324 kve->kve_protection & KVME_PROT_WRITE ? 'w' : '-',
325 kve->kve_protection & KVME_PROT_EXEC ? 'x' : '-');
326 }
327
328 /* Invoke the callback function to create the corefile segment.
329 Pass MODIFIED as true, we do not know the real modification state. */
330 func (kve->kve_start, size, kve->kve_protection & KVME_PROT_READ,
331 kve->kve_protection & KVME_PROT_WRITE,
332 kve->kve_protection & KVME_PROT_EXEC, 1, data);
333 }
334 return 0;
335}
336
337/* Implement the "info_proc" target_ops method. */
338
339bool
340nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
341{
342 pid_t pid;
49d1d1f5 343 bool do_cmdline = false;
b4848d2a 344 bool do_cwd = false;
51c133d5 345 bool do_exe = false;
54b8cbd0
KR
346 bool do_mappings = false;
347
348 switch (what)
349 {
1085dfd4
KR
350 case IP_MINIMAL:
351 do_cmdline = true;
352 do_cwd = true;
353 do_exe = true;
354 break;
54b8cbd0
KR
355 case IP_MAPPINGS:
356 do_mappings = true;
357 break;
49d1d1f5
KR
358 case IP_CMDLINE:
359 do_cmdline = true;
360 break;
51c133d5
KR
361 case IP_EXE:
362 do_exe = true;
363 break;
b4848d2a
KR
364 case IP_CWD:
365 do_cwd = true;
366 break;
1085dfd4
KR
367 case IP_ALL:
368 do_cmdline = true;
369 do_cwd = true;
370 do_exe = true;
371 do_mappings = true;
372 break;
54b8cbd0
KR
373 default:
374 error (_("Not supported on this target."));
375 }
376
377 gdb_argv built_argv (args);
378 if (built_argv.count () == 0)
379 {
380 pid = inferior_ptid.pid ();
381 if (pid == 0)
382 error (_("No current process: you must name one."));
383 }
384 else if (built_argv.count () == 1 && isdigit (built_argv[0][0]))
385 pid = strtol (built_argv[0], NULL, 10);
386 else
387 error (_("Invalid arguments."));
388
389 printf_filtered (_("process %d\n"), pid);
390
49d1d1f5
KR
391 if (do_cmdline)
392 {
393 gdb::unique_xmalloc_ptr<char[]> cmdline = nbsd_pid_to_cmdline (pid);
394 if (cmdline != nullptr)
395 printf_filtered ("cmdline = '%s'\n", cmdline.get ());
396 else
397 warning (_("unable to fetch command line"));
398 }
b4848d2a
KR
399 if (do_cwd)
400 {
401 std::string cwd = nbsd_pid_to_cwd (pid);
402 if (cwd != "")
403 printf_filtered ("cwd = '%s'\n", cwd.c_str ());
404 else
405 warning (_("unable to fetch current working directory"));
406 }
51c133d5
KR
407 if (do_exe)
408 {
409 const char *exe = pid_to_exec_file (pid);
410 if (exe != nullptr)
411 printf_filtered ("exe = '%s'\n", exe);
412 else
413 warning (_("unable to fetch executable path name"));
414 }
54b8cbd0
KR
415 if (do_mappings)
416 {
417 size_t nvment;
418 gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl
419 = nbsd_kinfo_get_vmmap (pid, &nvment);
420
421 if (vmentl != nullptr)
422 {
423 int addr_bit = TARGET_CHAR_BIT * sizeof (void *);
424 nbsd_info_proc_mappings_header (addr_bit);
425
426 struct kinfo_vmentry *kve = vmentl.get ();
427 for (int i = 0; i < nvment; i++, kve++)
428 nbsd_info_proc_mappings_entry (addr_bit, kve->kve_start,
429 kve->kve_end, kve->kve_offset,
430 kve->kve_flags, kve->kve_protection,
431 kve->kve_path);
432 }
433 else
434 warning (_("unable to fetch virtual memory map"));
435 }
436
437 return true;
438}
This page took 1.747506 seconds and 4 git commands to generate.