Commit | Line | Data |
---|---|---|
99cf6da6 KR |
1 | /* Internal interfaces for the NetBSD code. |
2 | ||
3666a048 | 3 | Copyright (C) 2006-2021 Free Software Foundation, Inc. |
99cf6da6 KR |
4 | |
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
c489f8c6 | 20 | #include "gdbsupport/common-defs.h" |
99cf6da6 | 21 | #include "nat/netbsd-nat.h" |
c489f8c6 | 22 | #include "gdbsupport/common-debug.h" |
99cf6da6 | 23 | |
330662f6 | 24 | #include <sys/types.h> |
feedfcc7 | 25 | #include <sys/ptrace.h> |
330662f6 KR |
26 | #include <sys/sysctl.h> |
27 | ||
c489f8c6 KR |
28 | #include <cstring> |
29 | ||
30 | #include "gdbsupport/function-view.h" | |
31 | ||
99cf6da6 KR |
32 | namespace netbsd_nat |
33 | { | |
330662f6 KR |
34 | |
35 | /* See netbsd-nat.h. */ | |
36 | ||
37 | const char * | |
38 | pid_to_exec_file (pid_t pid) | |
39 | { | |
40 | static char buf[PATH_MAX]; | |
41 | int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_PATHNAME}; | |
42 | size_t buflen = sizeof (buf); | |
43 | if (::sysctl (mib, ARRAY_SIZE (mib), buf, &buflen, NULL, 0) != 0) | |
44 | return NULL; | |
45 | return buf; | |
46 | } | |
47 | ||
c489f8c6 KR |
48 | /* Generic thread (LWP) lister within a specified PID. The CALLBACK |
49 | parameters is a C++ function that is called for each detected thread. | |
50 | When the CALLBACK function returns true, the iteration is interrupted. | |
51 | ||
52 | This function assumes internally that the queried process is stopped | |
53 | and the number of threads does not change between two sysctl () calls. */ | |
54 | ||
55 | static bool | |
56 | netbsd_thread_lister (const pid_t pid, | |
57 | gdb::function_view<bool (const struct kinfo_lwp *)> | |
58 | callback) | |
59 | { | |
60 | int mib[5] = {CTL_KERN, KERN_LWP, pid, sizeof (struct kinfo_lwp), 0}; | |
61 | size_t size; | |
62 | ||
63 | if (sysctl (mib, ARRAY_SIZE (mib), NULL, &size, NULL, 0) == -1 || size == 0) | |
64 | perror_with_name (("sysctl")); | |
65 | ||
66 | mib[4] = size / sizeof (size_t); | |
67 | ||
68 | gdb::unique_xmalloc_ptr<struct kinfo_lwp[]> kl | |
69 | ((struct kinfo_lwp *) xcalloc (size, 1)); | |
70 | ||
71 | if (sysctl (mib, ARRAY_SIZE (mib), kl.get (), &size, NULL, 0) == -1 | |
72 | || size == 0) | |
73 | perror_with_name (("sysctl")); | |
74 | ||
75 | for (size_t i = 0; i < size / sizeof (struct kinfo_lwp); i++) | |
76 | { | |
77 | struct kinfo_lwp *l = &kl[i]; | |
78 | ||
79 | /* Return true if the specified thread is alive. */ | |
80 | auto lwp_alive | |
81 | = [] (struct kinfo_lwp *lwp) | |
82 | { | |
83 | switch (lwp->l_stat) | |
84 | { | |
85 | case LSSLEEP: | |
86 | case LSRUN: | |
87 | case LSONPROC: | |
88 | case LSSTOP: | |
89 | case LSSUSPENDED: | |
90 | return true; | |
91 | default: | |
92 | return false; | |
93 | } | |
94 | }; | |
95 | ||
96 | /* Ignore embryonic or demised threads. */ | |
97 | if (!lwp_alive (l)) | |
98 | continue; | |
99 | ||
100 | if (callback (l)) | |
101 | return true; | |
102 | } | |
103 | ||
104 | return false; | |
105 | } | |
106 | ||
107 | /* See netbsd-nat.h. */ | |
108 | ||
109 | bool | |
110 | thread_alive (ptid_t ptid) | |
111 | { | |
112 | pid_t pid = ptid.pid (); | |
113 | lwpid_t lwp = ptid.lwp (); | |
114 | ||
115 | auto fn | |
116 | = [=] (const struct kinfo_lwp *kl) | |
117 | { | |
dda83cd7 | 118 | return kl->l_lid == lwp; |
c489f8c6 KR |
119 | }; |
120 | ||
121 | return netbsd_thread_lister (pid, fn); | |
122 | } | |
123 | ||
124 | /* See netbsd-nat.h. */ | |
125 | ||
126 | const char * | |
127 | thread_name (ptid_t ptid) | |
128 | { | |
129 | pid_t pid = ptid.pid (); | |
130 | lwpid_t lwp = ptid.lwp (); | |
131 | ||
132 | static char buf[KI_LNAMELEN] = {}; | |
133 | ||
134 | auto fn | |
135 | = [=] (const struct kinfo_lwp *kl) | |
136 | { | |
137 | if (kl->l_lid == lwp) | |
138 | { | |
139 | xsnprintf (buf, sizeof buf, "%s", kl->l_name); | |
140 | return true; | |
141 | } | |
142 | return false; | |
143 | }; | |
144 | ||
145 | if (netbsd_thread_lister (pid, fn)) | |
146 | return buf; | |
147 | else | |
148 | return NULL; | |
149 | } | |
150 | ||
151 | /* See netbsd-nat.h. */ | |
152 | ||
153 | void | |
154 | for_each_thread (pid_t pid, gdb::function_view<void (ptid_t)> callback) | |
155 | { | |
156 | auto fn | |
157 | = [=, &callback] (const struct kinfo_lwp *kl) | |
158 | { | |
159 | ptid_t ptid = ptid_t (pid, kl->l_lid, 0); | |
160 | callback (ptid); | |
161 | return false; | |
162 | }; | |
163 | ||
164 | netbsd_thread_lister (pid, fn); | |
165 | } | |
166 | ||
feedfcc7 KR |
167 | /* See netbsd-nat.h. */ |
168 | ||
169 | void | |
170 | enable_proc_events (pid_t pid) | |
171 | { | |
172 | int events; | |
173 | ||
174 | if (ptrace (PT_GET_EVENT_MASK, pid, &events, sizeof (events)) == -1) | |
175 | perror_with_name (("ptrace")); | |
176 | ||
177 | events |= PTRACE_LWP_CREATE; | |
178 | events |= PTRACE_LWP_EXIT; | |
179 | ||
180 | if (ptrace (PT_SET_EVENT_MASK, pid, &events, sizeof (events)) == -1) | |
181 | perror_with_name (("ptrace")); | |
182 | } | |
183 | ||
1ccb2c17 KR |
184 | /* See netbsd-nat.h. */ |
185 | ||
186 | int | |
187 | qxfer_siginfo (pid_t pid, const char *annex, unsigned char *readbuf, | |
188 | unsigned const char *writebuf, CORE_ADDR offset, int len) | |
189 | { | |
190 | ptrace_siginfo_t psi; | |
191 | ||
192 | if (offset > sizeof (siginfo_t)) | |
193 | return -1; | |
194 | ||
195 | if (ptrace (PT_GET_SIGINFO, pid, &psi, sizeof (psi)) == -1) | |
196 | return -1; | |
197 | ||
198 | if (offset + len > sizeof (siginfo_t)) | |
199 | len = sizeof (siginfo_t) - offset; | |
200 | ||
201 | if (readbuf != NULL) | |
202 | memcpy (readbuf, ((gdb_byte *) &psi.psi_siginfo) + offset, len); | |
203 | else | |
204 | { | |
205 | memcpy (((gdb_byte *) &psi.psi_siginfo) + offset, writebuf, len); | |
206 | ||
207 | if (ptrace (PT_SET_SIGINFO, pid, &psi, sizeof (psi)) == -1) | |
208 | return -1; | |
209 | } | |
210 | return len; | |
211 | } | |
212 | ||
91e5e8db KR |
213 | /* See netbsd-nat.h. */ |
214 | ||
215 | int | |
216 | write_memory (pid_t pid, unsigned const char *writebuf, CORE_ADDR offset, | |
217 | size_t len, size_t *xfered_len) | |
218 | { | |
219 | struct ptrace_io_desc io; | |
220 | io.piod_op = PIOD_WRITE_D; | |
221 | io.piod_len = len; | |
222 | ||
223 | size_t bytes_written = 0; | |
224 | ||
225 | /* Zero length write always succeeds. */ | |
226 | if (len > 0) | |
227 | { | |
228 | do | |
229 | { | |
230 | io.piod_addr = (void *)(writebuf + bytes_written); | |
231 | io.piod_offs = (void *)(offset + bytes_written); | |
232 | ||
233 | errno = 0; | |
234 | int rv = ptrace (PT_IO, pid, &io, 0); | |
235 | if (rv == -1) | |
236 | { | |
237 | gdb_assert (errno != 0); | |
238 | return errno; | |
239 | } | |
240 | if (io.piod_len == 0) | |
4641551a | 241 | break; |
91e5e8db KR |
242 | |
243 | bytes_written += io.piod_len; | |
244 | io.piod_len = len - bytes_written; | |
245 | } | |
246 | while (bytes_written < len); | |
247 | } | |
248 | ||
249 | if (xfered_len != nullptr) | |
250 | *xfered_len = bytes_written; | |
251 | ||
252 | return 0; | |
253 | } | |
254 | ||
255 | /* See netbsd-nat.h. */ | |
256 | ||
257 | int | |
258 | read_memory (pid_t pid, unsigned char *readbuf, CORE_ADDR offset, | |
259 | size_t len, size_t *xfered_len) | |
260 | { | |
261 | struct ptrace_io_desc io; | |
262 | io.piod_op = PIOD_READ_D; | |
263 | io.piod_len = len; | |
264 | ||
265 | size_t bytes_read = 0; | |
266 | ||
267 | /* Zero length read always succeeds. */ | |
268 | if (len > 0) | |
269 | { | |
270 | do | |
271 | { | |
272 | io.piod_offs = (void *)(offset + bytes_read); | |
273 | io.piod_addr = readbuf + bytes_read; | |
274 | ||
275 | int rv = ptrace (PT_IO, pid, &io, 0); | |
276 | if (rv == -1) | |
277 | return errno; | |
278 | if (io.piod_len == 0) | |
4641551a | 279 | break; |
91e5e8db KR |
280 | |
281 | bytes_read += io.piod_len; | |
282 | io.piod_len = len - bytes_read; | |
283 | } | |
284 | while (bytes_read < len); | |
285 | } | |
286 | ||
287 | if (xfered_len != nullptr) | |
288 | *xfered_len = bytes_read; | |
289 | ||
290 | return 0; | |
291 | } | |
292 | ||
99cf6da6 | 293 | } |