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