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