]> Git Repo - binutils.git/blob - gdb/nat/netbsd-nat.c
Automatic date update in version.in
[binutils.git] / gdb / nat / netbsd-nat.c
1 /* Internal interfaces for the NetBSD code.
2
3    Copyright (C) 2006-2022 Free Software Foundation, Inc.
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
20 #include "gdbsupport/common-defs.h"
21 #include "nat/netbsd-nat.h"
22 #include "gdbsupport/common-debug.h"
23
24 #include <sys/types.h>
25 #include <sys/ptrace.h>
26 #include <sys/sysctl.h>
27
28 #include <cstring>
29
30 #include "gdbsupport/function-view.h"
31
32 namespace netbsd_nat
33 {
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
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       {
118         return kl->l_lid == lwp;
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
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
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
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)
241             break;
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)
279             break;
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
293 }
This page took 0.040279 seconds and 4 git commands to generate.