Implement "info proc exe" 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 /* Generic thread (LWP) lister within a specified process. The callback
48 parameters is a C++ function that is called for each detected thread. */
49
50 static bool
51 nbsd_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
104 bool
105 nbsd_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
122 const char *
123 nbsd_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
150 static void
151 nbsd_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
172 void
173 nbsd_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
180 void
181 nbsd_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
190 std::string
191 nbsd_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 }
204
205 /* Retrieve all the memory regions in the specified process. */
206
207 static gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]>
208 nbsd_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
242 int
243 nbsd_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
298 bool
299 nbsd_nat_target::info_proc (const char *args, enum info_proc_what what)
300 {
301 pid_t pid;
302 bool do_exe = false;
303 bool do_mappings = false;
304
305 switch (what)
306 {
307 case IP_MAPPINGS:
308 do_mappings = true;
309 break;
310 case IP_EXE:
311 do_exe = true;
312 break;
313 default:
314 error (_("Not supported on this target."));
315 }
316
317 gdb_argv built_argv (args);
318 if (built_argv.count () == 0)
319 {
320 pid = inferior_ptid.pid ();
321 if (pid == 0)
322 error (_("No current process: you must name one."));
323 }
324 else if (built_argv.count () == 1 && isdigit (built_argv[0][0]))
325 pid = strtol (built_argv[0], NULL, 10);
326 else
327 error (_("Invalid arguments."));
328
329 printf_filtered (_("process %d\n"), pid);
330
331 if (do_exe)
332 {
333 const char *exe = pid_to_exec_file (pid);
334 if (exe != nullptr)
335 printf_filtered ("exe = '%s'\n", exe);
336 else
337 warning (_("unable to fetch executable path name"));
338 }
339 if (do_mappings)
340 {
341 size_t nvment;
342 gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl
343 = nbsd_kinfo_get_vmmap (pid, &nvment);
344
345 if (vmentl != nullptr)
346 {
347 int addr_bit = TARGET_CHAR_BIT * sizeof (void *);
348 nbsd_info_proc_mappings_header (addr_bit);
349
350 struct kinfo_vmentry *kve = vmentl.get ();
351 for (int i = 0; i < nvment; i++, kve++)
352 nbsd_info_proc_mappings_entry (addr_bit, kve->kve_start,
353 kve->kve_end, kve->kve_offset,
354 kve->kve_flags, kve->kve_protection,
355 kve->kve_path);
356 }
357 else
358 warning (_("unable to fetch virtual memory map"));
359 }
360
361 return true;
362 }
This page took 0.049547 seconds and 5 git commands to generate.