Commit | Line | Data |
---|---|---|
84c5b489 MK |
1 | /* Native-dependent code for NetBSD. |
2 | ||
3666a048 | 3 | Copyright (C) 2006-2021 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 | ||
135 | /* Implement the "post_startup_inferior" target_ops method. */ | |
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 | { | |
250 | fprintf_filtered (gdb_stdout, | |
251 | "Save segment, %ld bytes at %s (%c%c%c)\n", | |
252 | (long) size, | |
253 | paddress (target_gdbarch (), kve->kve_start), | |
254 | kve->kve_protection & KVME_PROT_READ ? 'r' : '-', | |
255 | kve->kve_protection & KVME_PROT_WRITE ? 'w' : '-', | |
256 | kve->kve_protection & KVME_PROT_EXEC ? 'x' : '-'); | |
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, | |
263 | kve->kve_protection & KVME_PROT_EXEC, 1, data); | |
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 | ||
326 | printf_filtered (_("process %d\n"), pid); | |
327 | ||
49d1d1f5 KR |
328 | if (do_cmdline) |
329 | { | |
330 | gdb::unique_xmalloc_ptr<char[]> cmdline = nbsd_pid_to_cmdline (pid); | |
331 | if (cmdline != nullptr) | |
332 | printf_filtered ("cmdline = '%s'\n", cmdline.get ()); | |
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 != "") | |
340 | printf_filtered ("cwd = '%s'\n", cwd.c_str ()); | |
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) | |
348 | printf_filtered ("exe = '%s'\n", exe); | |
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 | ||
402 | printf_filtered ("Name: %s\n", kp.p_comm); | |
403 | printf_filtered ("State: %s\n", process_status(kp.p_realstat)); | |
404 | printf_filtered ("Parent process: %" PRId32 "\n", kp.p_ppid); | |
405 | printf_filtered ("Process group: %" PRId32 "\n", kp.p__pgid); | |
406 | printf_filtered ("Session id: %" PRId32 "\n", kp.p_sid); | |
407 | printf_filtered ("TTY: %" PRId32 "\n", kp.p_tdev); | |
408 | printf_filtered ("TTY owner process group: %" PRId32 "\n", kp.p_tpgid); | |
409 | printf_filtered ("User IDs (real, effective, saved): " | |
410 | "%" PRIu32 " %" PRIu32 " %" PRIu32 "\n", | |
411 | kp.p_ruid, kp.p_uid, kp.p_svuid); | |
412 | printf_filtered ("Group IDs (real, effective, saved): " | |
413 | "%" PRIu32 " %" PRIu32 " %" PRIu32 "\n", | |
414 | kp.p_rgid, kp.p_gid, kp.p_svgid); | |
415 | ||
416 | printf_filtered ("Groups:"); | |
417 | for (int i = 0; i < kp.p_ngroups; i++) | |
418 | printf_filtered (" %" PRIu32, kp.p_groups[i]); | |
419 | printf_filtered ("\n"); | |
420 | printf_filtered ("Minor faults (no memory page): %" PRIu64 "\n", | |
421 | kp.p_uru_minflt); | |
422 | printf_filtered ("Major faults (memory page faults): %" PRIu64 "\n", | |
423 | kp.p_uru_majflt); | |
424 | printf_filtered ("utime: %" PRIu32 ".%06" PRIu32 "\n", | |
425 | kp.p_uutime_sec, kp.p_uutime_usec); | |
426 | printf_filtered ("stime: %" PRIu32 ".%06" PRIu32 "\n", | |
427 | kp.p_ustime_sec, kp.p_ustime_usec); | |
428 | printf_filtered ("utime+stime, children: %" PRIu32 ".%06" PRIu32 "\n", | |
429 | kp.p_uctime_sec, kp.p_uctime_usec); | |
430 | printf_filtered ("'nice' value: %" PRIu8 "\n", kp.p_nice); | |
431 | printf_filtered ("Start time: %" PRIu32 ".%06" PRIu32 "\n", | |
432 | kp.p_ustart_sec, kp.p_ustart_usec); | |
433 | int pgtok = getpagesize () / 1024; | |
434 | printf_filtered ("Data size: %" PRIuMAX " kB\n", | |
435 | (uintmax_t) kp.p_vm_dsize * pgtok); | |
436 | printf_filtered ("Stack size: %" PRIuMAX " kB\n", | |
437 | (uintmax_t) kp.p_vm_ssize * pgtok); | |
438 | printf_filtered ("Text size: %" PRIuMAX " kB\n", | |
439 | (uintmax_t) kp.p_vm_tsize * pgtok); | |
440 | printf_filtered ("Resident set size: %" PRIuMAX " kB\n", | |
441 | (uintmax_t) kp.p_vm_rssize * pgtok); | |
442 | printf_filtered ("Maximum RSS: %" PRIu64 " kB\n", kp.p_uru_maxrss); | |
443 | printf_filtered ("Pending Signals:"); | |
444 | for (size_t i = 0; i < ARRAY_SIZE (kp.p_siglist.__bits); i++) | |
445 | printf_filtered (" %08" PRIx32, kp.p_siglist.__bits[i]); | |
446 | printf_filtered ("\n"); | |
447 | printf_filtered ("Ignored Signals:"); | |
448 | for (size_t i = 0; i < ARRAY_SIZE (kp.p_sigignore.__bits); i++) | |
449 | printf_filtered (" %08" PRIx32, kp.p_sigignore.__bits[i]); | |
450 | printf_filtered ("\n"); | |
451 | printf_filtered ("Caught Signals:"); | |
452 | for (size_t i = 0; i < ARRAY_SIZE (kp.p_sigcatch.__bits); i++) | |
453 | printf_filtered (" %08" PRIx32, kp.p_sigcatch.__bits[i]); | |
454 | printf_filtered ("\n"); | |
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 | ||
512 | if (catch_syscall_enabled () > 0) | |
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 | ||
551 | do | |
552 | { | |
553 | /* The common code passes WNOHANG that leads to crashes, overwrite it. */ | |
554 | pid = waitpid (ptid.pid (), &status, 0); | |
555 | } | |
556 | while (pid == -1 && errno == EINTR); | |
557 | ||
558 | clear_sigint_trap (); | |
559 | ||
560 | if (pid == -1) | |
561 | perror_with_name (_("Child process unexpectedly missing")); | |
562 | ||
563 | store_waitstatus (ourstatus, status); | |
564 | return pid; | |
565 | } | |
566 | ||
567 | /* Wait for the child specified by PTID to do something. Return the | |
568 | process ID of the child, or MINUS_ONE_PTID in case of error; store | |
569 | the status in *OURSTATUS. */ | |
570 | ||
571 | ptid_t | |
572 | nbsd_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, | |
b60cea74 | 573 | target_wait_flags target_options) |
f94b2e03 KR |
574 | { |
575 | pid_t pid = nbsd_wait (ptid, ourstatus, target_options); | |
576 | ptid_t wptid = ptid_t (pid); | |
577 | ||
578 | /* If the child stopped, keep investigating its status. */ | |
579 | if (ourstatus->kind != TARGET_WAITKIND_STOPPED) | |
580 | return wptid; | |
581 | ||
582 | /* Extract the event and thread that received a signal. */ | |
583 | ptrace_siginfo_t psi; | |
584 | if (ptrace (PT_GET_SIGINFO, pid, &psi, sizeof (psi)) == -1) | |
585 | perror_with_name (("ptrace")); | |
586 | ||
587 | /* Pick child's siginfo_t. */ | |
588 | siginfo_t *si = &psi.psi_siginfo; | |
589 | ||
590 | int lwp = psi.psi_lwpid; | |
591 | ||
592 | int signo = si->si_signo; | |
593 | const int code = si->si_code; | |
594 | ||
595 | /* Construct PTID with a specified thread that received the event. | |
596 | If a signal was targeted to the whole process, lwp is 0. */ | |
597 | wptid = ptid_t (pid, lwp, 0); | |
598 | ||
599 | /* Bail out on non-debugger oriented signals.. */ | |
600 | if (signo != SIGTRAP) | |
601 | return wptid; | |
602 | ||
603 | /* Stop examining non-debugger oriented SIGTRAP codes. */ | |
604 | if (code <= SI_USER || code == SI_NOINFO) | |
605 | return wptid; | |
606 | ||
117539e6 KR |
607 | /* Process state for threading events */ |
608 | ptrace_state_t pst = {}; | |
609 | if (code == TRAP_LWP) | |
610 | { | |
611 | if (ptrace (PT_GET_PROCESS_STATE, pid, &pst, sizeof (pst)) == -1) | |
612 | perror_with_name (("ptrace")); | |
613 | } | |
614 | ||
615 | if (code == TRAP_LWP && pst.pe_report_event == PTRACE_LWP_EXIT) | |
616 | { | |
617 | /* If GDB attaches to a multi-threaded process, exiting | |
618 | threads might be skipped during post_attach that | |
619 | have not yet reported their PTRACE_LWP_EXIT event. | |
620 | Ignore exited events for an unknown LWP. */ | |
621 | thread_info *thr = find_thread_ptid (this, wptid); | |
622 | if (thr == nullptr) | |
623 | ourstatus->kind = TARGET_WAITKIND_SPURIOUS; | |
624 | else | |
625 | { | |
626 | ourstatus->kind = TARGET_WAITKIND_THREAD_EXITED; | |
627 | /* NetBSD does not store an LWP exit status. */ | |
628 | ourstatus->value.integer = 0; | |
629 | ||
630 | if (print_thread_events) | |
631 | printf_unfiltered (_("[%s exited]\n"), | |
632 | target_pid_to_str (wptid).c_str ()); | |
633 | delete_thread (thr); | |
634 | } | |
635 | ||
636 | /* The GDB core expects that the rest of the threads are running. */ | |
637 | if (ptrace (PT_CONTINUE, pid, (void *) 1, 0) == -1) | |
638 | perror_with_name (("ptrace")); | |
639 | ||
640 | return wptid; | |
641 | } | |
642 | ||
f94b2e03 KR |
643 | if (in_thread_list (this, ptid_t (pid))) |
644 | thread_change_ptid (this, ptid_t (pid), wptid); | |
645 | ||
117539e6 KR |
646 | if (code == TRAP_LWP && pst.pe_report_event == PTRACE_LWP_CREATE) |
647 | { | |
648 | /* If GDB attaches to a multi-threaded process, newborn | |
649 | threads might be added by nbsd_add_threads that have | |
650 | not yet reported their PTRACE_LWP_CREATE event. Ignore | |
651 | born events for an already-known LWP. */ | |
652 | if (in_thread_list (this, wptid)) | |
653 | ourstatus->kind = TARGET_WAITKIND_SPURIOUS; | |
654 | else | |
655 | { | |
656 | add_thread (this, wptid); | |
657 | ourstatus->kind = TARGET_WAITKIND_THREAD_CREATED; | |
658 | } | |
659 | return wptid; | |
660 | } | |
661 | ||
f94b2e03 KR |
662 | if (code == TRAP_EXEC) |
663 | { | |
664 | ourstatus->kind = TARGET_WAITKIND_EXECD; | |
665 | ourstatus->value.execd_pathname = xstrdup (pid_to_exec_file (pid)); | |
666 | return wptid; | |
667 | } | |
668 | ||
669 | if (code == TRAP_TRACE) | |
670 | { | |
671 | /* Unhandled at this level. */ | |
672 | return wptid; | |
673 | } | |
674 | ||
675 | if (code == TRAP_SCE || code == TRAP_SCX) | |
676 | { | |
677 | int sysnum = si->si_sysnum; | |
678 | ||
679 | if (!catch_syscall_enabled () || !catching_syscall_number (sysnum)) | |
680 | { | |
681 | /* If the core isn't interested in this event, ignore it. */ | |
682 | ourstatus->kind = TARGET_WAITKIND_SPURIOUS; | |
683 | return wptid; | |
684 | } | |
685 | ||
686 | ourstatus->kind = | |
687 | (code == TRAP_SCE) ? TARGET_WAITKIND_SYSCALL_ENTRY : | |
688 | TARGET_WAITKIND_SYSCALL_RETURN; | |
689 | ourstatus->value.syscall_number = sysnum; | |
690 | return wptid; | |
691 | } | |
692 | ||
693 | if (code == TRAP_BRKPT) | |
694 | { | |
695 | /* Unhandled at this level. */ | |
696 | return wptid; | |
697 | } | |
698 | ||
699 | /* Unclassified SIGTRAP event. */ | |
700 | ourstatus->kind = TARGET_WAITKIND_SPURIOUS; | |
701 | return wptid; | |
702 | } | |
703 | ||
704 | /* Implement the "insert_exec_catchpoint" target_ops method. */ | |
705 | ||
706 | int | |
707 | nbsd_nat_target::insert_exec_catchpoint (int pid) | |
708 | { | |
709 | /* Nothing to do. */ | |
710 | return 0; | |
711 | } | |
712 | ||
713 | /* Implement the "remove_exec_catchpoint" target_ops method. */ | |
714 | ||
715 | int | |
716 | nbsd_nat_target::remove_exec_catchpoint (int pid) | |
717 | { | |
718 | /* Nothing to do. */ | |
719 | return 0; | |
720 | } | |
721 | ||
722 | /* Implement the "set_syscall_catchpoint" target_ops method. */ | |
723 | ||
724 | int | |
725 | nbsd_nat_target::set_syscall_catchpoint (int pid, bool needed, | |
dda83cd7 SM |
726 | int any_count, |
727 | gdb::array_view<const int> syscall_counts) | |
f94b2e03 KR |
728 | { |
729 | /* Ignore the arguments. inf-ptrace.c will use PT_SYSCALL which | |
730 | will catch all system call entries and exits. The system calls | |
731 | are filtered by GDB rather than the kernel. */ | |
732 | return 0; | |
733 | } | |
1de14d77 KR |
734 | |
735 | /* Implement the "supports_multi_process" target_ops method. */ | |
736 | ||
737 | bool | |
738 | nbsd_nat_target::supports_multi_process () | |
739 | { | |
740 | return true; | |
741 | } | |
4d46f402 KR |
742 | |
743 | /* Implement the "xfer_partial" target_ops method. */ | |
744 | ||
745 | enum target_xfer_status | |
746 | nbsd_nat_target::xfer_partial (enum target_object object, | |
747 | const char *annex, gdb_byte *readbuf, | |
748 | const gdb_byte *writebuf, | |
749 | ULONGEST offset, ULONGEST len, | |
750 | ULONGEST *xfered_len) | |
751 | { | |
752 | pid_t pid = inferior_ptid.pid (); | |
753 | ||
754 | switch (object) | |
755 | { | |
756 | case TARGET_OBJECT_SIGNAL_INFO: | |
757 | { | |
cf4ac4be KR |
758 | len = netbsd_nat::qxfer_siginfo(pid, annex, readbuf, writebuf, offset, |
759 | len); | |
4d46f402 | 760 | |
cf4ac4be | 761 | if (len == -1) |
4d46f402 KR |
762 | return TARGET_XFER_E_IO; |
763 | ||
4d46f402 KR |
764 | *xfered_len = len; |
765 | return TARGET_XFER_OK; | |
766 | } | |
91e5e8db KR |
767 | case TARGET_OBJECT_MEMORY: |
768 | { | |
769 | size_t xfered; | |
770 | int res; | |
771 | if (writebuf != nullptr) | |
772 | res = netbsd_nat::write_memory (pid, writebuf, offset, len, &xfered); | |
773 | else | |
774 | res = netbsd_nat::read_memory (pid, readbuf, offset, len, &xfered); | |
775 | if (res != 0) | |
776 | { | |
777 | if (res == EACCES) | |
778 | fprintf_unfiltered (gdb_stderr, "Cannot %s process at %s (%s). " | |
779 | "Is PaX MPROTECT active? See security(7), " | |
780 | "sysctl(7), paxctl(8)\n", | |
781 | (writebuf ? "write to" : "read from"), | |
782 | pulongest (offset), safe_strerror (errno)); | |
783 | return TARGET_XFER_E_IO; | |
784 | } | |
785 | if (xfered == 0) | |
786 | return TARGET_XFER_EOF; | |
787 | *xfered_len = (ULONGEST) xfered; | |
788 | return TARGET_XFER_OK; | |
789 | } | |
4d46f402 KR |
790 | default: |
791 | return inf_ptrace_target::xfer_partial (object, annex, | |
792 | readbuf, writebuf, offset, | |
793 | len, xfered_len); | |
794 | } | |
795 | } | |
a6e6223e KR |
796 | |
797 | /* Implement the "supports_dumpcore" target_ops method. */ | |
798 | ||
799 | bool | |
800 | nbsd_nat_target::supports_dumpcore () | |
801 | { | |
802 | return true; | |
803 | } | |
804 | ||
805 | /* Implement the "dumpcore" target_ops method. */ | |
806 | ||
807 | void | |
808 | nbsd_nat_target::dumpcore (const char *filename) | |
809 | { | |
810 | pid_t pid = inferior_ptid.pid (); | |
811 | ||
812 | if (ptrace (PT_DUMPCORE, pid, const_cast<char *>(filename), | |
813 | strlen (filename)) == -1) | |
814 | perror_with_name (("ptrace")); | |
815 | } |