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