xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/nat/netbsd-nat.c (revision 2dd295436a0082eb4f8d294f4aa73c223413d0f2)
1 /* Internal interfaces for the NetBSD code.
2 
3    Copyright (C) 2006-2020 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 }
214