xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/agent.cc (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /* Shared utility routines for GDB to interact with agent.
2 
3    Copyright (C) 2009-2023 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 "common-defs.h"
21 #include "target/target.h"
22 #include "gdbsupport/symbol.h"
23 #include <unistd.h>
24 #include "filestuff.h"
25 
26 #define IPA_SYM_STRUCT_NAME ipa_sym_addresses_common
27 #include "agent.h"
28 
29 bool debug_agent = false;
30 
31 /* A stdarg wrapper for debug_vprintf.  */
32 
33 static void ATTRIBUTE_PRINTF (1, 2)
34 debug_agent_printf (const char *fmt, ...)
35 {
36   va_list ap;
37 
38   if (!debug_agent)
39     return;
40   va_start (ap, fmt);
41   debug_vprintf (fmt, ap);
42   va_end (ap);
43 }
44 
45 #define DEBUG_AGENT debug_agent_printf
46 
47 /* Global flag to determine using agent or not.  */
48 bool use_agent = false;
49 
50 /* Addresses of in-process agent's symbols both GDB and GDBserver cares
51    about.  */
52 
53 struct ipa_sym_addresses_common
54 {
55   CORE_ADDR addr_helper_thread_id;
56   CORE_ADDR addr_cmd_buf;
57   CORE_ADDR addr_capability;
58 };
59 
60 /* Cache of the helper thread id.  FIXME: this global should be made
61    per-process.  */
62 static uint32_t helper_thread_id = 0;
63 
64 static struct
65 {
66   const char *name;
67   int offset;
68 } symbol_list[] = {
69   IPA_SYM(helper_thread_id),
70   IPA_SYM(cmd_buf),
71   IPA_SYM(capability),
72 };
73 
74 static struct ipa_sym_addresses_common ipa_sym_addrs;
75 
76 static bool all_agent_symbols_looked_up = false;
77 
78 bool
79 agent_loaded_p (void)
80 {
81   return all_agent_symbols_looked_up;
82 }
83 
84 /* Look up all symbols needed by agent.  Return 0 if all the symbols are
85    found, return non-zero otherwise.  */
86 
87 int
88 agent_look_up_symbols (void *arg)
89 {
90   all_agent_symbols_looked_up = false;
91 
92   for (int i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++)
93     {
94       CORE_ADDR *addrp =
95 	(CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset);
96       struct objfile *objfile = (struct objfile *) arg;
97 
98       if (find_minimal_symbol_address (symbol_list[i].name, addrp,
99 				       objfile) != 0)
100 	{
101 	  DEBUG_AGENT ("symbol `%s' not found\n", symbol_list[i].name);
102 	  return -1;
103 	}
104     }
105 
106   all_agent_symbols_looked_up = true;
107   return 0;
108 }
109 
110 static unsigned int
111 agent_get_helper_thread_id (void)
112 {
113   if  (helper_thread_id == 0)
114     {
115       if (target_read_uint32 (ipa_sym_addrs.addr_helper_thread_id,
116 			      &helper_thread_id))
117 	warning (_("Error reading helper thread's id in lib"));
118     }
119 
120   return helper_thread_id;
121 }
122 
123 #ifdef HAVE_SYS_UN_H
124 #include <sys/socket.h>
125 #include <sys/un.h>
126 #define SOCK_DIR P_tmpdir
127 
128 #ifndef UNIX_PATH_MAX
129 #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path)
130 #endif
131 
132 #endif
133 
134 /* Connects to synchronization socket.  PID is the pid of inferior, which is
135    used to set up the connection socket.  */
136 
137 static int
138 gdb_connect_sync_socket (int pid)
139 {
140 #ifdef HAVE_SYS_UN_H
141   struct sockaddr_un addr = {};
142   int res, fd;
143   char path[UNIX_PATH_MAX];
144 
145   res = xsnprintf (path, UNIX_PATH_MAX, "%s/gdb_ust%d", P_tmpdir, pid);
146   if (res >= UNIX_PATH_MAX)
147     return -1;
148 
149   res = fd = gdb_socket_cloexec (PF_UNIX, SOCK_STREAM, 0);
150   if (res == -1)
151     {
152       warning (_("error opening sync socket: %s"), safe_strerror (errno));
153       return -1;
154     }
155 
156   addr.sun_family = AF_UNIX;
157 
158   res = xsnprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path);
159   if (res >= UNIX_PATH_MAX)
160     {
161       warning (_("string overflow allocating socket name"));
162       close (fd);
163       return -1;
164     }
165 
166   res = connect (fd, (struct sockaddr *) &addr, sizeof (addr));
167   if (res == -1)
168     {
169       warning (_("error connecting sync socket (%s): %s. "
170 		 "Make sure the directory exists and that it is writable."),
171 		 path, safe_strerror (errno));
172       close (fd);
173       return -1;
174     }
175 
176   return fd;
177 #else
178   return -1;
179 #endif
180 }
181 
182 /* Execute an agent command in the inferior.  PID is the value of pid of the
183    inferior.  CMD is the buffer for command.  GDB or GDBserver will store the
184    command into it and fetch the return result from CMD.  The interaction
185    between GDB/GDBserver and the agent is synchronized by a synchronization
186    socket.  Return zero if success, otherwise return non-zero.  */
187 
188 int
189 agent_run_command (int pid, const char *cmd, int len)
190 {
191   int fd;
192   int tid = agent_get_helper_thread_id ();
193   ptid_t ptid = ptid_t (pid, tid);
194 
195   int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf,
196 				 (gdb_byte *) cmd, len);
197 
198   if (ret != 0)
199     {
200       warning (_("unable to write"));
201       return -1;
202     }
203 
204   DEBUG_AGENT ("agent: resumed helper thread\n");
205 
206   /* Resume helper thread.  */
207   target_continue_no_signal (ptid);
208 
209   fd = gdb_connect_sync_socket (pid);
210   if (fd >= 0)
211     {
212       char buf[1] = "";
213 
214       DEBUG_AGENT ("agent: signalling helper thread\n");
215 
216       do
217 	{
218 	  ret = write (fd, buf, 1);
219 	} while (ret == -1 && errno == EINTR);
220 
221 	DEBUG_AGENT ("agent: waiting for helper thread's response\n");
222 
223       do
224 	{
225 	  ret = read (fd, buf, 1);
226 	} while (ret == -1 && errno == EINTR);
227 
228       close (fd);
229 
230       DEBUG_AGENT ("agent: helper thread's response received\n");
231     }
232   else
233     return -1;
234 
235   /* Need to read response with the inferior stopped.  */
236   if (ptid != null_ptid)
237     {
238       /* Stop thread PTID.  */
239       DEBUG_AGENT ("agent: stop helper thread\n");
240       target_stop_and_wait (ptid);
241     }
242 
243   if (fd >= 0)
244     {
245       if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd,
246 			      IPA_CMD_BUF_SIZE))
247 	{
248 	  warning (_("Error reading command response"));
249 	  return -1;
250 	}
251     }
252 
253   return 0;
254 }
255 
256 /* Each bit of it stands for a capability of agent.  */
257 static uint32_t agent_capability = 0;
258 
259 /* Return true if agent has capability AGENT_CAP, otherwise return false.  */
260 
261 bool
262 agent_capability_check (enum agent_capa agent_capa)
263 {
264   if (agent_capability == 0)
265     {
266       if (target_read_uint32 (ipa_sym_addrs.addr_capability,
267 			      &agent_capability))
268 	warning (_("Error reading capability of agent"));
269     }
270   return (agent_capability & agent_capa) != 0;
271 }
272 
273 /* Invalidate the cache of agent capability, so we'll read it from inferior
274    again.  Call it when launches a new program or reconnect to remote stub.  */
275 
276 void
277 agent_capability_invalidate (void)
278 {
279   agent_capability = 0;
280 }
281