1 /* Internal interfaces for the NetBSD code.
2 
3    Copyright (C) 2006-2021 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 *
pid_to_exec_file(pid_t pid)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
netbsd_thread_lister(const pid_t pid,gdb::function_view<bool (const struct kinfo_lwp *)> callback)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
thread_alive(ptid_t ptid)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 *
thread_name(ptid_t ptid)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
for_each_thread(pid_t pid,gdb::function_view<void (ptid_t)> callback)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
enable_proc_events(pid_t pid)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
qxfer_siginfo(pid_t pid,const char * annex,unsigned char * readbuf,unsigned const char * writebuf,CORE_ADDR offset,int len)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
write_memory(pid_t pid,unsigned const char * writebuf,CORE_ADDR offset,size_t len,size_t * xfered_len)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
read_memory(pid_t pid,unsigned char * readbuf,CORE_ADDR offset,size_t len,size_t * xfered_len)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 }
294