]>
Commit | Line | Data |
---|---|---|
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> | |
f94b2e03 | 31 | #include <sys/wait.h> |
a2ecbe9f | 32 | |
766062f6 | 33 | /* Return the name of a file that can be opened to get the symbols for |
84c5b489 MK |
34 | the child process identified by PID. */ |
35 | ||
36 | char * | |
f6ac5f3d | 37 | nbsd_nat_target::pid_to_exec_file (int pid) |
84c5b489 | 38 | { |
b4ab256d | 39 | static char buf[PATH_MAX]; |
a2ecbe9f KR |
40 | size_t buflen; |
41 | int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_PATHNAME}; | |
42 | buflen = sizeof (buf); | |
43 | if (sysctl (mib, ARRAY_SIZE (mib), buf, &buflen, NULL, 0)) | |
44 | return NULL; | |
45 | return buf; | |
84c5b489 | 46 | } |
05f00e22 | 47 | |
b4848d2a KR |
48 | /* Return the current directory for the process identified by PID. */ |
49 | ||
50 | static std::string | |
51 | nbsd_pid_to_cwd (int pid) | |
52 | { | |
53 | char buf[PATH_MAX]; | |
54 | size_t buflen; | |
55 | int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_CWD}; | |
56 | buflen = sizeof (buf); | |
57 | if (sysctl (mib, ARRAY_SIZE (mib), buf, &buflen, NULL, 0)) | |
58 | return ""; | |
59 | return buf; | |
60 | } | |
61 | ||
06ca5dd4 KR |
62 | /* Return the kinfo_proc2 structure for the process identified by PID. */ |
63 | ||
64 | static bool | |
65 | nbsd_pid_to_kinfo_proc2 (pid_t pid, struct kinfo_proc2 *kp) | |
66 | { | |
67 | gdb_assert (kp != nullptr); | |
68 | ||
69 | size_t size = sizeof (*kp); | |
70 | int mib[6] = {CTL_KERN, KERN_PROC2, KERN_PROC_PID, pid, | |
71 | static_cast<int> (size), 1}; | |
72 | return !sysctl (mib, ARRAY_SIZE (mib), kp, &size, NULL, 0); | |
73 | } | |
74 | ||
49d1d1f5 KR |
75 | /* Return the command line for the process identified by PID. */ |
76 | ||
77 | static gdb::unique_xmalloc_ptr<char[]> | |
78 | nbsd_pid_to_cmdline (int pid) | |
79 | { | |
80 | int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV}; | |
81 | ||
82 | size_t size = 0; | |
83 | if (sysctl (mib, ARRAY_SIZE (mib), NULL, &size, NULL, 0) == -1 || size == 0) | |
84 | return nullptr; | |
85 | ||
86 | gdb::unique_xmalloc_ptr<char[]> args (XNEWVAR (char, size)); | |
87 | ||
88 | if (sysctl (mib, ARRAY_SIZE (mib), args.get (), &size, NULL, 0) == -1 | |
89 | || size == 0) | |
90 | return nullptr; | |
91 | ||
92 | /* Arguments are returned as a flattened string with NUL separators. | |
93 | Join the arguments with spaces to form a single string. */ | |
94 | for (size_t i = 0; i < size - 1; i++) | |
95 | if (args[i] == '\0') | |
96 | args[i] = ' '; | |
97 | args[size - 1] = '\0'; | |
98 | ||
99 | return args; | |
100 | } | |
101 | ||
05f00e22 KR |
102 | /* Generic thread (LWP) lister within a specified process. The callback |
103 | parameters is a C++ function that is called for each detected thread. */ | |
104 | ||
105 | static bool | |
106 | nbsd_thread_lister (const pid_t pid, | |
107 | gdb::function_view<bool (const struct kinfo_lwp *)> | |
108 | callback) | |
109 | { | |
110 | int mib[5] = {CTL_KERN, KERN_LWP, pid, sizeof (struct kinfo_lwp), 0}; | |
111 | size_t size; | |
112 | ||
113 | if (sysctl (mib, ARRAY_SIZE (mib), NULL, &size, NULL, 0) == -1 || size == 0) | |
114 | perror_with_name (("sysctl")); | |
115 | ||
116 | mib[4] = size / sizeof (size_t); | |
117 | ||
118 | gdb::unique_xmalloc_ptr<struct kinfo_lwp[]> kl | |
119 | ((struct kinfo_lwp *) xcalloc (size, 1)); | |
120 | ||
121 | if (sysctl (mib, ARRAY_SIZE (mib), kl.get (), &size, NULL, 0) == -1 | |
122 | || size == 0) | |
123 | perror_with_name (("sysctl")); | |
124 | ||
125 | for (size_t i = 0; i < size / sizeof (struct kinfo_lwp); i++) | |
126 | { | |
127 | struct kinfo_lwp *l = &kl[i]; | |
128 | ||
129 | /* Return true if the specified thread is alive. */ | |
130 | auto lwp_alive | |
131 | = [] (struct kinfo_lwp *lwp) | |
132 | { | |
133 | switch (lwp->l_stat) | |
134 | { | |
135 | case LSSLEEP: | |
136 | case LSRUN: | |
137 | case LSONPROC: | |
138 | case LSSTOP: | |
139 | case LSSUSPENDED: | |
140 | return true; | |
141 | default: | |
142 | return false; | |
143 | } | |
144 | }; | |
145 | ||
146 | /* Ignore embryonic or demised threads. */ | |
147 | if (!lwp_alive (l)) | |
148 | continue; | |
149 | ||
150 | if (callback (l)) | |
151 | return true; | |
152 | } | |
153 | ||
154 | return false; | |
155 | } | |
156 | ||
157 | /* Return true if PTID is still active in the inferior. */ | |
158 | ||
159 | bool | |
160 | nbsd_nat_target::thread_alive (ptid_t ptid) | |
161 | { | |
162 | pid_t pid = ptid.pid (); | |
163 | int lwp = ptid.lwp (); | |
164 | ||
165 | auto fn | |
166 | = [&lwp] (const struct kinfo_lwp *kl) | |
167 | { | |
168 | return kl->l_lid == lwp; | |
169 | }; | |
170 | ||
171 | return nbsd_thread_lister (pid, fn); | |
172 | } | |
173 | ||
174 | /* Return the name assigned to a thread by an application. Returns | |
175 | the string in a static buffer. */ | |
176 | ||
177 | const char * | |
178 | nbsd_nat_target::thread_name (struct thread_info *thr) | |
179 | { | |
180 | ptid_t ptid = thr->ptid; | |
181 | pid_t pid = ptid.pid (); | |
182 | int lwp = ptid.lwp (); | |
183 | ||
184 | static char buf[KI_LNAMELEN] = {}; | |
185 | ||
186 | auto fn | |
187 | = [&lwp] (const struct kinfo_lwp *kl) | |
188 | { | |
189 | if (kl->l_lid == lwp) | |
190 | { | |
191 | xsnprintf (buf, sizeof buf, "%s", kl->l_name); | |
192 | return true; | |
193 | } | |
194 | return false; | |
195 | }; | |
196 | ||
197 | if (nbsd_thread_lister (pid, fn)) | |
198 | return buf; | |
199 | else | |
200 | return NULL; | |
201 | } | |
202 | ||
203 | /* Implement the "post_attach" target_ops method. */ | |
204 | ||
205 | static void | |
206 | nbsd_add_threads (nbsd_nat_target *target, pid_t pid) | |
207 | { | |
208 | auto fn | |
209 | = [&target, &pid] (const struct kinfo_lwp *kl) | |
210 | { | |
211 | ptid_t ptid = ptid_t (pid, kl->l_lid, 0); | |
212 | if (!in_thread_list (target, ptid)) | |
213 | { | |
214 | if (inferior_ptid.lwp () == 0) | |
215 | thread_change_ptid (target, inferior_ptid, ptid); | |
216 | else | |
217 | add_thread (target, ptid); | |
218 | } | |
219 | return false; | |
220 | }; | |
221 | ||
222 | nbsd_thread_lister (pid, fn); | |
223 | } | |
224 | ||
225 | /* Implement the "post_attach" target_ops method. */ | |
226 | ||
227 | void | |
228 | nbsd_nat_target::post_attach (int pid) | |
229 | { | |
230 | nbsd_add_threads (this, pid); | |
231 | } | |
232 | ||
233 | /* Implement the "update_thread_list" target_ops method. */ | |
234 | ||
235 | void | |
236 | nbsd_nat_target::update_thread_list () | |
237 | { | |
238 | prune_threads (); | |
239 | ||
240 | nbsd_add_threads (this, inferior_ptid.pid ()); | |
241 | } | |
242 | ||
243 | /* Convert PTID to a string. */ | |
244 | ||
245 | std::string | |
246 | nbsd_nat_target::pid_to_str (ptid_t ptid) | |
247 | { | |
248 | int lwp = ptid.lwp (); | |
249 | ||
250 | if (lwp != 0) | |
251 | { | |
252 | pid_t pid = ptid.pid (); | |
253 | ||
254 | return string_printf ("LWP %d of process %d", lwp, pid); | |
255 | } | |
256 | ||
257 | return normal_pid_to_str (ptid); | |
258 | } | |
54b8cbd0 KR |
259 | |
260 | /* Retrieve all the memory regions in the specified process. */ | |
261 | ||
262 | static gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> | |
263 | nbsd_kinfo_get_vmmap (pid_t pid, size_t *size) | |
264 | { | |
265 | int mib[5] = {CTL_VM, VM_PROC, VM_PROC_MAP, pid, | |
266 | sizeof (struct kinfo_vmentry)}; | |
267 | ||
268 | size_t length = 0; | |
269 | if (sysctl (mib, ARRAY_SIZE (mib), NULL, &length, NULL, 0)) | |
270 | { | |
271 | *size = 0; | |
272 | return NULL; | |
273 | } | |
274 | ||
275 | /* Prereserve more space. The length argument is volatile and can change | |
276 | between the sysctl(3) calls as this function can be called against a | |
277 | running process. */ | |
278 | length = length * 5 / 3; | |
279 | ||
280 | gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> kiv | |
281 | (XNEWVAR (kinfo_vmentry, length)); | |
282 | ||
283 | if (sysctl (mib, ARRAY_SIZE (mib), kiv.get (), &length, NULL, 0)) | |
284 | { | |
285 | *size = 0; | |
286 | return NULL; | |
287 | } | |
288 | ||
289 | *size = length / sizeof (struct kinfo_vmentry); | |
290 | return kiv; | |
291 | } | |
292 | ||
293 | /* Iterate over all the memory regions in the current inferior, | |
294 | calling FUNC for each memory region. OBFD is passed as the last | |
295 | argument to FUNC. */ | |
296 | ||
297 | int | |
298 | nbsd_nat_target::find_memory_regions (find_memory_region_ftype func, | |
299 | void *data) | |
300 | { | |
301 | pid_t pid = inferior_ptid.pid (); | |
302 | ||
303 | size_t nitems; | |
304 | gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl | |
305 | = nbsd_kinfo_get_vmmap (pid, &nitems); | |
306 | if (vmentl == NULL) | |
307 | perror_with_name (_("Couldn't fetch VM map entries.")); | |
308 | ||
309 | for (size_t i = 0; i < nitems; i++) | |
310 | { | |
311 | struct kinfo_vmentry *kve = &vmentl[i]; | |
312 | ||
313 | /* Skip unreadable segments and those where MAP_NOCORE has been set. */ | |
314 | if (!(kve->kve_protection & KVME_PROT_READ) | |
315 | || kve->kve_flags & KVME_FLAG_NOCOREDUMP) | |
316 | continue; | |
317 | ||
318 | /* Skip segments with an invalid type. */ | |
319 | switch (kve->kve_type) | |
320 | { | |
321 | case KVME_TYPE_VNODE: | |
322 | case KVME_TYPE_ANON: | |
323 | case KVME_TYPE_SUBMAP: | |
324 | case KVME_TYPE_OBJECT: | |
325 | break; | |
326 | default: | |
327 | continue; | |
328 | } | |
329 | ||
330 | size_t size = kve->kve_end - kve->kve_start; | |
331 | if (info_verbose) | |
332 | { | |
333 | fprintf_filtered (gdb_stdout, | |
334 | "Save segment, %ld bytes at %s (%c%c%c)\n", | |
335 | (long) size, | |
336 | paddress (target_gdbarch (), kve->kve_start), | |
337 | kve->kve_protection & KVME_PROT_READ ? 'r' : '-', | |
338 | kve->kve_protection & KVME_PROT_WRITE ? 'w' : '-', | |
339 | kve->kve_protection & KVME_PROT_EXEC ? 'x' : '-'); | |
340 | } | |
341 | ||
342 | /* Invoke the callback function to create the corefile segment. | |
343 | Pass MODIFIED as true, we do not know the real modification state. */ | |
344 | func (kve->kve_start, size, kve->kve_protection & KVME_PROT_READ, | |
345 | kve->kve_protection & KVME_PROT_WRITE, | |
346 | kve->kve_protection & KVME_PROT_EXEC, 1, data); | |
347 | } | |
348 | return 0; | |
349 | } | |
350 | ||
351 | /* Implement the "info_proc" target_ops method. */ | |
352 | ||
353 | bool | |
354 | nbsd_nat_target::info_proc (const char *args, enum info_proc_what what) | |
355 | { | |
356 | pid_t pid; | |
49d1d1f5 | 357 | bool do_cmdline = false; |
b4848d2a | 358 | bool do_cwd = false; |
51c133d5 | 359 | bool do_exe = false; |
54b8cbd0 | 360 | bool do_mappings = false; |
06ca5dd4 | 361 | bool do_status = false; |
54b8cbd0 KR |
362 | |
363 | switch (what) | |
364 | { | |
1085dfd4 KR |
365 | case IP_MINIMAL: |
366 | do_cmdline = true; | |
367 | do_cwd = true; | |
368 | do_exe = true; | |
369 | break; | |
06ca5dd4 KR |
370 | case IP_STAT: |
371 | case IP_STATUS: | |
372 | do_status = true; | |
373 | break; | |
54b8cbd0 KR |
374 | case IP_MAPPINGS: |
375 | do_mappings = true; | |
376 | break; | |
49d1d1f5 KR |
377 | case IP_CMDLINE: |
378 | do_cmdline = true; | |
379 | break; | |
51c133d5 KR |
380 | case IP_EXE: |
381 | do_exe = true; | |
382 | break; | |
b4848d2a KR |
383 | case IP_CWD: |
384 | do_cwd = true; | |
385 | break; | |
1085dfd4 KR |
386 | case IP_ALL: |
387 | do_cmdline = true; | |
388 | do_cwd = true; | |
389 | do_exe = true; | |
390 | do_mappings = true; | |
06ca5dd4 | 391 | do_status = true; |
1085dfd4 | 392 | break; |
54b8cbd0 KR |
393 | default: |
394 | error (_("Not supported on this target.")); | |
395 | } | |
396 | ||
397 | gdb_argv built_argv (args); | |
398 | if (built_argv.count () == 0) | |
399 | { | |
400 | pid = inferior_ptid.pid (); | |
401 | if (pid == 0) | |
402 | error (_("No current process: you must name one.")); | |
403 | } | |
404 | else if (built_argv.count () == 1 && isdigit (built_argv[0][0])) | |
405 | pid = strtol (built_argv[0], NULL, 10); | |
406 | else | |
407 | error (_("Invalid arguments.")); | |
408 | ||
409 | printf_filtered (_("process %d\n"), pid); | |
410 | ||
49d1d1f5 KR |
411 | if (do_cmdline) |
412 | { | |
413 | gdb::unique_xmalloc_ptr<char[]> cmdline = nbsd_pid_to_cmdline (pid); | |
414 | if (cmdline != nullptr) | |
415 | printf_filtered ("cmdline = '%s'\n", cmdline.get ()); | |
416 | else | |
417 | warning (_("unable to fetch command line")); | |
418 | } | |
b4848d2a KR |
419 | if (do_cwd) |
420 | { | |
421 | std::string cwd = nbsd_pid_to_cwd (pid); | |
422 | if (cwd != "") | |
423 | printf_filtered ("cwd = '%s'\n", cwd.c_str ()); | |
424 | else | |
425 | warning (_("unable to fetch current working directory")); | |
426 | } | |
51c133d5 KR |
427 | if (do_exe) |
428 | { | |
429 | const char *exe = pid_to_exec_file (pid); | |
430 | if (exe != nullptr) | |
431 | printf_filtered ("exe = '%s'\n", exe); | |
432 | else | |
433 | warning (_("unable to fetch executable path name")); | |
434 | } | |
54b8cbd0 KR |
435 | if (do_mappings) |
436 | { | |
437 | size_t nvment; | |
438 | gdb::unique_xmalloc_ptr<struct kinfo_vmentry[]> vmentl | |
439 | = nbsd_kinfo_get_vmmap (pid, &nvment); | |
440 | ||
441 | if (vmentl != nullptr) | |
442 | { | |
443 | int addr_bit = TARGET_CHAR_BIT * sizeof (void *); | |
444 | nbsd_info_proc_mappings_header (addr_bit); | |
445 | ||
446 | struct kinfo_vmentry *kve = vmentl.get (); | |
447 | for (int i = 0; i < nvment; i++, kve++) | |
448 | nbsd_info_proc_mappings_entry (addr_bit, kve->kve_start, | |
449 | kve->kve_end, kve->kve_offset, | |
450 | kve->kve_flags, kve->kve_protection, | |
451 | kve->kve_path); | |
452 | } | |
453 | else | |
454 | warning (_("unable to fetch virtual memory map")); | |
455 | } | |
06ca5dd4 KR |
456 | if (do_status) |
457 | { | |
458 | struct kinfo_proc2 kp; | |
459 | if (!nbsd_pid_to_kinfo_proc2 (pid, &kp)) | |
460 | warning (_("Failed to fetch process information")); | |
461 | else | |
462 | { | |
463 | auto process_status | |
464 | = [] (int8_t stat) | |
465 | { | |
466 | switch (stat) | |
467 | { | |
468 | case SIDL: | |
469 | return "IDL"; | |
470 | case SACTIVE: | |
471 | return "ACTIVE"; | |
472 | case SDYING: | |
473 | return "DYING"; | |
474 | case SSTOP: | |
475 | return "STOP"; | |
476 | case SZOMB: | |
477 | return "ZOMB"; | |
478 | case SDEAD: | |
479 | return "DEAD"; | |
480 | default: | |
481 | return "? (unknown)"; | |
482 | } | |
483 | }; | |
484 | ||
485 | printf_filtered ("Name: %s\n", kp.p_comm); | |
486 | printf_filtered ("State: %s\n", process_status(kp.p_realstat)); | |
487 | printf_filtered ("Parent process: %" PRId32 "\n", kp.p_ppid); | |
488 | printf_filtered ("Process group: %" PRId32 "\n", kp.p__pgid); | |
489 | printf_filtered ("Session id: %" PRId32 "\n", kp.p_sid); | |
490 | printf_filtered ("TTY: %" PRId32 "\n", kp.p_tdev); | |
491 | printf_filtered ("TTY owner process group: %" PRId32 "\n", kp.p_tpgid); | |
492 | printf_filtered ("User IDs (real, effective, saved): " | |
493 | "%" PRIu32 " %" PRIu32 " %" PRIu32 "\n", | |
494 | kp.p_ruid, kp.p_uid, kp.p_svuid); | |
495 | printf_filtered ("Group IDs (real, effective, saved): " | |
496 | "%" PRIu32 " %" PRIu32 " %" PRIu32 "\n", | |
497 | kp.p_rgid, kp.p_gid, kp.p_svgid); | |
498 | ||
499 | printf_filtered ("Groups:"); | |
500 | for (int i = 0; i < kp.p_ngroups; i++) | |
501 | printf_filtered (" %" PRIu32, kp.p_groups[i]); | |
502 | printf_filtered ("\n"); | |
503 | printf_filtered ("Minor faults (no memory page): %" PRIu64 "\n", | |
504 | kp.p_uru_minflt); | |
505 | printf_filtered ("Major faults (memory page faults): %" PRIu64 "\n", | |
506 | kp.p_uru_majflt); | |
507 | printf_filtered ("utime: %" PRIu32 ".%06" PRIu32 "\n", | |
508 | kp.p_uutime_sec, kp.p_uutime_usec); | |
509 | printf_filtered ("stime: %" PRIu32 ".%06" PRIu32 "\n", | |
510 | kp.p_ustime_sec, kp.p_ustime_usec); | |
511 | printf_filtered ("utime+stime, children: %" PRIu32 ".%06" PRIu32 "\n", | |
512 | kp.p_uctime_sec, kp.p_uctime_usec); | |
513 | printf_filtered ("'nice' value: %" PRIu8 "\n", kp.p_nice); | |
514 | printf_filtered ("Start time: %" PRIu32 ".%06" PRIu32 "\n", | |
515 | kp.p_ustart_sec, kp.p_ustart_usec); | |
516 | int pgtok = getpagesize () / 1024; | |
517 | printf_filtered ("Data size: %" PRIuMAX " kB\n", | |
518 | (uintmax_t) kp.p_vm_dsize * pgtok); | |
519 | printf_filtered ("Stack size: %" PRIuMAX " kB\n", | |
520 | (uintmax_t) kp.p_vm_ssize * pgtok); | |
521 | printf_filtered ("Text size: %" PRIuMAX " kB\n", | |
522 | (uintmax_t) kp.p_vm_tsize * pgtok); | |
523 | printf_filtered ("Resident set size: %" PRIuMAX " kB\n", | |
524 | (uintmax_t) kp.p_vm_rssize * pgtok); | |
525 | printf_filtered ("Maximum RSS: %" PRIu64 " kB\n", kp.p_uru_maxrss); | |
526 | printf_filtered ("Pending Signals:"); | |
527 | for (size_t i = 0; i < ARRAY_SIZE (kp.p_siglist.__bits); i++) | |
528 | printf_filtered (" %08" PRIx32, kp.p_siglist.__bits[i]); | |
529 | printf_filtered ("\n"); | |
530 | printf_filtered ("Ignored Signals:"); | |
531 | for (size_t i = 0; i < ARRAY_SIZE (kp.p_sigignore.__bits); i++) | |
532 | printf_filtered (" %08" PRIx32, kp.p_sigignore.__bits[i]); | |
533 | printf_filtered ("\n"); | |
534 | printf_filtered ("Caught Signals:"); | |
535 | for (size_t i = 0; i < ARRAY_SIZE (kp.p_sigcatch.__bits); i++) | |
536 | printf_filtered (" %08" PRIx32, kp.p_sigcatch.__bits[i]); | |
537 | printf_filtered ("\n"); | |
538 | } | |
539 | } | |
54b8cbd0 KR |
540 | |
541 | return true; | |
542 | } | |
f94b2e03 KR |
543 | |
544 | /* Resume execution of a specified PTID, that points to a process or a thread | |
545 | within a process. If one thread is specified, all other threads are | |
546 | suspended. If STEP is nonzero, single-step it. If SIGNAL is nonzero, | |
547 | give it that signal. */ | |
548 | ||
549 | static void | |
550 | nbsd_resume(nbsd_nat_target *target, ptid_t ptid, int step, | |
551 | enum gdb_signal signal) | |
552 | { | |
553 | int request; | |
554 | ||
555 | gdb_assert (minus_one_ptid != ptid); | |
556 | ||
557 | if (ptid.lwp_p ()) | |
558 | { | |
559 | /* If ptid is a specific LWP, suspend all other LWPs in the process. */ | |
560 | inferior *inf = find_inferior_ptid (target, ptid); | |
561 | ||
562 | for (thread_info *tp : inf->non_exited_threads ()) | |
563 | { | |
564 | if (tp->ptid.lwp () == ptid.lwp ()) | |
565 | request = PT_RESUME; | |
566 | else | |
567 | request = PT_SUSPEND; | |
568 | ||
569 | if (ptrace (request, tp->ptid.pid (), NULL, tp->ptid.lwp ()) == -1) | |
570 | perror_with_name (("ptrace")); | |
571 | } | |
572 | } | |
573 | else | |
574 | { | |
575 | /* If ptid is a wildcard, resume all matching threads (they won't run | |
576 | until the process is continued however). */ | |
577 | for (thread_info *tp : all_non_exited_threads (target, ptid)) | |
578 | if (ptrace (PT_RESUME, tp->ptid.pid (), NULL, tp->ptid.lwp ()) == -1) | |
579 | perror_with_name (("ptrace")); | |
580 | } | |
581 | ||
582 | if (step) | |
583 | { | |
584 | for (thread_info *tp : all_non_exited_threads (target, ptid)) | |
585 | if (ptrace (PT_SETSTEP, tp->ptid.pid (), NULL, tp->ptid.lwp ()) == -1) | |
586 | perror_with_name (("ptrace")); | |
587 | } | |
588 | else | |
589 | { | |
590 | for (thread_info *tp : all_non_exited_threads (target, ptid)) | |
591 | if (ptrace (PT_CLEARSTEP, tp->ptid.pid (), NULL, tp->ptid.lwp ()) == -1) | |
592 | perror_with_name (("ptrace")); | |
593 | } | |
594 | ||
595 | if (catch_syscall_enabled () > 0) | |
596 | request = PT_SYSCALL; | |
597 | else | |
598 | request = PT_CONTINUE; | |
599 | ||
600 | /* An address of (void *)1 tells ptrace to continue from | |
601 | where it was. If GDB wanted it to start some other way, we have | |
602 | already written a new program counter value to the child. */ | |
603 | if (ptrace (request, ptid.pid (), (void *)1, gdb_signal_to_host (signal)) == -1) | |
604 | perror_with_name (("ptrace")); | |
605 | } | |
606 | ||
607 | /* Resume execution of thread PTID, or all threads of all inferiors | |
608 | if PTID is -1. If STEP is nonzero, single-step it. If SIGNAL is nonzero, | |
609 | give it that signal. */ | |
610 | ||
611 | void | |
612 | nbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signal) | |
613 | { | |
614 | if (minus_one_ptid != ptid) | |
615 | nbsd_resume (this, ptid, step, signal); | |
616 | else | |
617 | { | |
618 | for (inferior *inf : all_non_exited_inferiors (this)) | |
619 | nbsd_resume (this, ptid_t (inf->pid, 0, 0), step, signal); | |
620 | } | |
621 | } | |
622 | ||
623 | /* Implement a safe wrapper around waitpid(). */ | |
624 | ||
625 | static pid_t | |
626 | nbsd_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options) | |
627 | { | |
628 | pid_t pid; | |
629 | int status; | |
630 | ||
631 | set_sigint_trap (); | |
632 | ||
633 | do | |
634 | { | |
635 | /* The common code passes WNOHANG that leads to crashes, overwrite it. */ | |
636 | pid = waitpid (ptid.pid (), &status, 0); | |
637 | } | |
638 | while (pid == -1 && errno == EINTR); | |
639 | ||
640 | clear_sigint_trap (); | |
641 | ||
642 | if (pid == -1) | |
643 | perror_with_name (_("Child process unexpectedly missing")); | |
644 | ||
645 | store_waitstatus (ourstatus, status); | |
646 | return pid; | |
647 | } | |
648 | ||
649 | /* Wait for the child specified by PTID to do something. Return the | |
650 | process ID of the child, or MINUS_ONE_PTID in case of error; store | |
651 | the status in *OURSTATUS. */ | |
652 | ||
653 | ptid_t | |
654 | nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, | |
655 | int target_options) | |
656 | { | |
657 | pid_t pid = nbsd_wait (ptid, ourstatus, target_options); | |
658 | ptid_t wptid = ptid_t (pid); | |
659 | ||
660 | /* If the child stopped, keep investigating its status. */ | |
661 | if (ourstatus->kind != TARGET_WAITKIND_STOPPED) | |
662 | return wptid; | |
663 | ||
664 | /* Extract the event and thread that received a signal. */ | |
665 | ptrace_siginfo_t psi; | |
666 | if (ptrace (PT_GET_SIGINFO, pid, &psi, sizeof (psi)) == -1) | |
667 | perror_with_name (("ptrace")); | |
668 | ||
669 | /* Pick child's siginfo_t. */ | |
670 | siginfo_t *si = &psi.psi_siginfo; | |
671 | ||
672 | int lwp = psi.psi_lwpid; | |
673 | ||
674 | int signo = si->si_signo; | |
675 | const int code = si->si_code; | |
676 | ||
677 | /* Construct PTID with a specified thread that received the event. | |
678 | If a signal was targeted to the whole process, lwp is 0. */ | |
679 | wptid = ptid_t (pid, lwp, 0); | |
680 | ||
681 | /* Bail out on non-debugger oriented signals.. */ | |
682 | if (signo != SIGTRAP) | |
683 | return wptid; | |
684 | ||
685 | /* Stop examining non-debugger oriented SIGTRAP codes. */ | |
686 | if (code <= SI_USER || code == SI_NOINFO) | |
687 | return wptid; | |
688 | ||
689 | if (in_thread_list (this, ptid_t (pid))) | |
690 | thread_change_ptid (this, ptid_t (pid), wptid); | |
691 | ||
692 | if (code == TRAP_EXEC) | |
693 | { | |
694 | ourstatus->kind = TARGET_WAITKIND_EXECD; | |
695 | ourstatus->value.execd_pathname = xstrdup (pid_to_exec_file (pid)); | |
696 | return wptid; | |
697 | } | |
698 | ||
699 | if (code == TRAP_TRACE) | |
700 | { | |
701 | /* Unhandled at this level. */ | |
702 | return wptid; | |
703 | } | |
704 | ||
705 | if (code == TRAP_SCE || code == TRAP_SCX) | |
706 | { | |
707 | int sysnum = si->si_sysnum; | |
708 | ||
709 | if (!catch_syscall_enabled () || !catching_syscall_number (sysnum)) | |
710 | { | |
711 | /* If the core isn't interested in this event, ignore it. */ | |
712 | ourstatus->kind = TARGET_WAITKIND_SPURIOUS; | |
713 | return wptid; | |
714 | } | |
715 | ||
716 | ourstatus->kind = | |
717 | (code == TRAP_SCE) ? TARGET_WAITKIND_SYSCALL_ENTRY : | |
718 | TARGET_WAITKIND_SYSCALL_RETURN; | |
719 | ourstatus->value.syscall_number = sysnum; | |
720 | return wptid; | |
721 | } | |
722 | ||
723 | if (code == TRAP_BRKPT) | |
724 | { | |
725 | /* Unhandled at this level. */ | |
726 | return wptid; | |
727 | } | |
728 | ||
729 | /* Unclassified SIGTRAP event. */ | |
730 | ourstatus->kind = TARGET_WAITKIND_SPURIOUS; | |
731 | return wptid; | |
732 | } | |
733 | ||
734 | /* Implement the "insert_exec_catchpoint" target_ops method. */ | |
735 | ||
736 | int | |
737 | nbsd_nat_target::insert_exec_catchpoint (int pid) | |
738 | { | |
739 | /* Nothing to do. */ | |
740 | return 0; | |
741 | } | |
742 | ||
743 | /* Implement the "remove_exec_catchpoint" target_ops method. */ | |
744 | ||
745 | int | |
746 | nbsd_nat_target::remove_exec_catchpoint (int pid) | |
747 | { | |
748 | /* Nothing to do. */ | |
749 | return 0; | |
750 | } | |
751 | ||
752 | /* Implement the "set_syscall_catchpoint" target_ops method. */ | |
753 | ||
754 | int | |
755 | nbsd_nat_target::set_syscall_catchpoint (int pid, bool needed, | |
756 | int any_count, | |
757 | gdb::array_view<const int> syscall_counts) | |
758 | { | |
759 | /* Ignore the arguments. inf-ptrace.c will use PT_SYSCALL which | |
760 | will catch all system call entries and exits. The system calls | |
761 | are filtered by GDB rather than the kernel. */ | |
762 | return 0; | |
763 | } |