xref: /netbsd-src/external/gpl3/gdb.old/dist/gdbsupport/agent.cc (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
17d62b00eSchristos /* Shared utility routines for GDB to interact with agent.
27d62b00eSchristos 
3*6881a400Schristos    Copyright (C) 2009-2023 Free Software Foundation, Inc.
47d62b00eSchristos 
57d62b00eSchristos    This file is part of GDB.
67d62b00eSchristos 
77d62b00eSchristos    This program is free software; you can redistribute it and/or modify
87d62b00eSchristos    it under the terms of the GNU General Public License as published by
97d62b00eSchristos    the Free Software Foundation; either version 3 of the License, or
107d62b00eSchristos    (at your option) any later version.
117d62b00eSchristos 
127d62b00eSchristos    This program is distributed in the hope that it will be useful,
137d62b00eSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
147d62b00eSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
157d62b00eSchristos    GNU General Public License for more details.
167d62b00eSchristos 
177d62b00eSchristos    You should have received a copy of the GNU General Public License
187d62b00eSchristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
197d62b00eSchristos 
207d62b00eSchristos #include "common-defs.h"
217d62b00eSchristos #include "target/target.h"
227d62b00eSchristos #include "gdbsupport/symbol.h"
237d62b00eSchristos #include <unistd.h>
247d62b00eSchristos #include "filestuff.h"
257d62b00eSchristos 
267d62b00eSchristos #define IPA_SYM_STRUCT_NAME ipa_sym_addresses_common
277d62b00eSchristos #include "agent.h"
287d62b00eSchristos 
297d62b00eSchristos bool debug_agent = false;
307d62b00eSchristos 
317d62b00eSchristos /* A stdarg wrapper for debug_vprintf.  */
327d62b00eSchristos 
337d62b00eSchristos static void ATTRIBUTE_PRINTF (1, 2)
347d62b00eSchristos debug_agent_printf (const char *fmt, ...)
357d62b00eSchristos {
367d62b00eSchristos   va_list ap;
377d62b00eSchristos 
387d62b00eSchristos   if (!debug_agent)
397d62b00eSchristos     return;
407d62b00eSchristos   va_start (ap, fmt);
417d62b00eSchristos   debug_vprintf (fmt, ap);
427d62b00eSchristos   va_end (ap);
437d62b00eSchristos }
447d62b00eSchristos 
457d62b00eSchristos #define DEBUG_AGENT debug_agent_printf
467d62b00eSchristos 
477d62b00eSchristos /* Global flag to determine using agent or not.  */
487d62b00eSchristos bool use_agent = false;
497d62b00eSchristos 
507d62b00eSchristos /* Addresses of in-process agent's symbols both GDB and GDBserver cares
517d62b00eSchristos    about.  */
527d62b00eSchristos 
537d62b00eSchristos struct ipa_sym_addresses_common
547d62b00eSchristos {
557d62b00eSchristos   CORE_ADDR addr_helper_thread_id;
567d62b00eSchristos   CORE_ADDR addr_cmd_buf;
577d62b00eSchristos   CORE_ADDR addr_capability;
587d62b00eSchristos };
597d62b00eSchristos 
607d62b00eSchristos /* Cache of the helper thread id.  FIXME: this global should be made
617d62b00eSchristos    per-process.  */
627d62b00eSchristos static uint32_t helper_thread_id = 0;
637d62b00eSchristos 
647d62b00eSchristos static struct
657d62b00eSchristos {
667d62b00eSchristos   const char *name;
677d62b00eSchristos   int offset;
687d62b00eSchristos } symbol_list[] = {
697d62b00eSchristos   IPA_SYM(helper_thread_id),
707d62b00eSchristos   IPA_SYM(cmd_buf),
717d62b00eSchristos   IPA_SYM(capability),
727d62b00eSchristos };
737d62b00eSchristos 
747d62b00eSchristos static struct ipa_sym_addresses_common ipa_sym_addrs;
757d62b00eSchristos 
767d62b00eSchristos static bool all_agent_symbols_looked_up = false;
777d62b00eSchristos 
787d62b00eSchristos bool
797d62b00eSchristos agent_loaded_p (void)
807d62b00eSchristos {
817d62b00eSchristos   return all_agent_symbols_looked_up;
827d62b00eSchristos }
837d62b00eSchristos 
847d62b00eSchristos /* Look up all symbols needed by agent.  Return 0 if all the symbols are
857d62b00eSchristos    found, return non-zero otherwise.  */
867d62b00eSchristos 
877d62b00eSchristos int
887d62b00eSchristos agent_look_up_symbols (void *arg)
897d62b00eSchristos {
907d62b00eSchristos   all_agent_symbols_looked_up = false;
917d62b00eSchristos 
927d62b00eSchristos   for (int i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++)
937d62b00eSchristos     {
947d62b00eSchristos       CORE_ADDR *addrp =
957d62b00eSchristos 	(CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset);
967d62b00eSchristos       struct objfile *objfile = (struct objfile *) arg;
977d62b00eSchristos 
987d62b00eSchristos       if (find_minimal_symbol_address (symbol_list[i].name, addrp,
997d62b00eSchristos 				       objfile) != 0)
1007d62b00eSchristos 	{
1017d62b00eSchristos 	  DEBUG_AGENT ("symbol `%s' not found\n", symbol_list[i].name);
1027d62b00eSchristos 	  return -1;
1037d62b00eSchristos 	}
1047d62b00eSchristos     }
1057d62b00eSchristos 
1067d62b00eSchristos   all_agent_symbols_looked_up = true;
1077d62b00eSchristos   return 0;
1087d62b00eSchristos }
1097d62b00eSchristos 
1107d62b00eSchristos static unsigned int
1117d62b00eSchristos agent_get_helper_thread_id (void)
1127d62b00eSchristos {
1137d62b00eSchristos   if  (helper_thread_id == 0)
1147d62b00eSchristos     {
1157d62b00eSchristos       if (target_read_uint32 (ipa_sym_addrs.addr_helper_thread_id,
1167d62b00eSchristos 			      &helper_thread_id))
1177d62b00eSchristos 	warning (_("Error reading helper thread's id in lib"));
1187d62b00eSchristos     }
1197d62b00eSchristos 
1207d62b00eSchristos   return helper_thread_id;
1217d62b00eSchristos }
1227d62b00eSchristos 
1237d62b00eSchristos #ifdef HAVE_SYS_UN_H
1247d62b00eSchristos #include <sys/socket.h>
1257d62b00eSchristos #include <sys/un.h>
1267d62b00eSchristos #define SOCK_DIR P_tmpdir
1277d62b00eSchristos 
1287d62b00eSchristos #ifndef UNIX_PATH_MAX
1297d62b00eSchristos #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path)
1307d62b00eSchristos #endif
1317d62b00eSchristos 
1327d62b00eSchristos #endif
1337d62b00eSchristos 
1347d62b00eSchristos /* Connects to synchronization socket.  PID is the pid of inferior, which is
1357d62b00eSchristos    used to set up the connection socket.  */
1367d62b00eSchristos 
1377d62b00eSchristos static int
1387d62b00eSchristos gdb_connect_sync_socket (int pid)
1397d62b00eSchristos {
1407d62b00eSchristos #ifdef HAVE_SYS_UN_H
1417d62b00eSchristos   struct sockaddr_un addr = {};
1427d62b00eSchristos   int res, fd;
1437d62b00eSchristos   char path[UNIX_PATH_MAX];
1447d62b00eSchristos 
1457d62b00eSchristos   res = xsnprintf (path, UNIX_PATH_MAX, "%s/gdb_ust%d", P_tmpdir, pid);
1467d62b00eSchristos   if (res >= UNIX_PATH_MAX)
1477d62b00eSchristos     return -1;
1487d62b00eSchristos 
1497d62b00eSchristos   res = fd = gdb_socket_cloexec (PF_UNIX, SOCK_STREAM, 0);
1507d62b00eSchristos   if (res == -1)
1517d62b00eSchristos     {
1527d62b00eSchristos       warning (_("error opening sync socket: %s"), safe_strerror (errno));
1537d62b00eSchristos       return -1;
1547d62b00eSchristos     }
1557d62b00eSchristos 
1567d62b00eSchristos   addr.sun_family = AF_UNIX;
1577d62b00eSchristos 
1587d62b00eSchristos   res = xsnprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path);
1597d62b00eSchristos   if (res >= UNIX_PATH_MAX)
1607d62b00eSchristos     {
1617d62b00eSchristos       warning (_("string overflow allocating socket name"));
1627d62b00eSchristos       close (fd);
1637d62b00eSchristos       return -1;
1647d62b00eSchristos     }
1657d62b00eSchristos 
1667d62b00eSchristos   res = connect (fd, (struct sockaddr *) &addr, sizeof (addr));
1677d62b00eSchristos   if (res == -1)
1687d62b00eSchristos     {
1697d62b00eSchristos       warning (_("error connecting sync socket (%s): %s. "
1707d62b00eSchristos 		 "Make sure the directory exists and that it is writable."),
1717d62b00eSchristos 		 path, safe_strerror (errno));
1727d62b00eSchristos       close (fd);
1737d62b00eSchristos       return -1;
1747d62b00eSchristos     }
1757d62b00eSchristos 
1767d62b00eSchristos   return fd;
1777d62b00eSchristos #else
1787d62b00eSchristos   return -1;
1797d62b00eSchristos #endif
1807d62b00eSchristos }
1817d62b00eSchristos 
1827d62b00eSchristos /* Execute an agent command in the inferior.  PID is the value of pid of the
1837d62b00eSchristos    inferior.  CMD is the buffer for command.  GDB or GDBserver will store the
1847d62b00eSchristos    command into it and fetch the return result from CMD.  The interaction
1857d62b00eSchristos    between GDB/GDBserver and the agent is synchronized by a synchronization
1867d62b00eSchristos    socket.  Return zero if success, otherwise return non-zero.  */
1877d62b00eSchristos 
1887d62b00eSchristos int
1897d62b00eSchristos agent_run_command (int pid, const char *cmd, int len)
1907d62b00eSchristos {
1917d62b00eSchristos   int fd;
1927d62b00eSchristos   int tid = agent_get_helper_thread_id ();
193*6881a400Schristos   ptid_t ptid = ptid_t (pid, tid);
1947d62b00eSchristos 
1957d62b00eSchristos   int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf,
1967d62b00eSchristos 				 (gdb_byte *) cmd, len);
1977d62b00eSchristos 
1987d62b00eSchristos   if (ret != 0)
1997d62b00eSchristos     {
2007d62b00eSchristos       warning (_("unable to write"));
2017d62b00eSchristos       return -1;
2027d62b00eSchristos     }
2037d62b00eSchristos 
2047d62b00eSchristos   DEBUG_AGENT ("agent: resumed helper thread\n");
2057d62b00eSchristos 
2067d62b00eSchristos   /* Resume helper thread.  */
2077d62b00eSchristos   target_continue_no_signal (ptid);
2087d62b00eSchristos 
2097d62b00eSchristos   fd = gdb_connect_sync_socket (pid);
2107d62b00eSchristos   if (fd >= 0)
2117d62b00eSchristos     {
2127d62b00eSchristos       char buf[1] = "";
2137d62b00eSchristos 
2147d62b00eSchristos       DEBUG_AGENT ("agent: signalling helper thread\n");
2157d62b00eSchristos 
2167d62b00eSchristos       do
2177d62b00eSchristos 	{
2187d62b00eSchristos 	  ret = write (fd, buf, 1);
2197d62b00eSchristos 	} while (ret == -1 && errno == EINTR);
2207d62b00eSchristos 
2217d62b00eSchristos 	DEBUG_AGENT ("agent: waiting for helper thread's response\n");
2227d62b00eSchristos 
2237d62b00eSchristos       do
2247d62b00eSchristos 	{
2257d62b00eSchristos 	  ret = read (fd, buf, 1);
2267d62b00eSchristos 	} while (ret == -1 && errno == EINTR);
2277d62b00eSchristos 
2287d62b00eSchristos       close (fd);
2297d62b00eSchristos 
2307d62b00eSchristos       DEBUG_AGENT ("agent: helper thread's response received\n");
2317d62b00eSchristos     }
2327d62b00eSchristos   else
2337d62b00eSchristos     return -1;
2347d62b00eSchristos 
2357d62b00eSchristos   /* Need to read response with the inferior stopped.  */
2367d62b00eSchristos   if (ptid != null_ptid)
2377d62b00eSchristos     {
2387d62b00eSchristos       /* Stop thread PTID.  */
2397d62b00eSchristos       DEBUG_AGENT ("agent: stop helper thread\n");
2407d62b00eSchristos       target_stop_and_wait (ptid);
2417d62b00eSchristos     }
2427d62b00eSchristos 
2437d62b00eSchristos   if (fd >= 0)
2447d62b00eSchristos     {
2457d62b00eSchristos       if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd,
2467d62b00eSchristos 			      IPA_CMD_BUF_SIZE))
2477d62b00eSchristos 	{
2487d62b00eSchristos 	  warning (_("Error reading command response"));
2497d62b00eSchristos 	  return -1;
2507d62b00eSchristos 	}
2517d62b00eSchristos     }
2527d62b00eSchristos 
2537d62b00eSchristos   return 0;
2547d62b00eSchristos }
2557d62b00eSchristos 
2567d62b00eSchristos /* Each bit of it stands for a capability of agent.  */
2577d62b00eSchristos static uint32_t agent_capability = 0;
2587d62b00eSchristos 
2597d62b00eSchristos /* Return true if agent has capability AGENT_CAP, otherwise return false.  */
2607d62b00eSchristos 
2617d62b00eSchristos bool
2627d62b00eSchristos agent_capability_check (enum agent_capa agent_capa)
2637d62b00eSchristos {
2647d62b00eSchristos   if (agent_capability == 0)
2657d62b00eSchristos     {
2667d62b00eSchristos       if (target_read_uint32 (ipa_sym_addrs.addr_capability,
2677d62b00eSchristos 			      &agent_capability))
2687d62b00eSchristos 	warning (_("Error reading capability of agent"));
2697d62b00eSchristos     }
2707d62b00eSchristos   return (agent_capability & agent_capa) != 0;
2717d62b00eSchristos }
2727d62b00eSchristos 
2737d62b00eSchristos /* Invalidate the cache of agent capability, so we'll read it from inferior
2747d62b00eSchristos    again.  Call it when launches a new program or reconnect to remote stub.  */
2757d62b00eSchristos 
2767d62b00eSchristos void
2777d62b00eSchristos agent_capability_invalidate (void)
2787d62b00eSchristos {
2797d62b00eSchristos   agent_capability = 0;
2807d62b00eSchristos }
281