/* Shared utility routines for GDB to interact with agent.
- Copyright (C) 2009-2012 Free Software Foundation, Inc.
+ Copyright (C) 2009-2019 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#ifdef GDBSERVER
-#include "server.h"
-#else
-#include "defs.h"
-#include "target.h"
-#include "inferior.h" /* for non_stop */
-#endif
-
-#include <string.h>
+#include "common-defs.h"
+#include "target/target.h"
+#include "common/symbol.h"
#include <unistd.h>
+#include "filestuff.h"
+
+#define IPA_SYM_STRUCT_NAME ipa_sym_addresses_common
#include "agent.h"
int debug_agent = 0;
-#ifdef GDBSERVER
-#define DEBUG_AGENT(fmt, args...) \
- if (debug_agent) \
- fprintf (stderr, fmt, ##args);
-#else
-#define DEBUG_AGENT(fmt, args...) \
- if (debug_agent) \
- fprintf_unfiltered (gdb_stdlog, fmt, ##args);
-#endif
+/* A stdarg wrapper for debug_vprintf. */
+
+static void ATTRIBUTE_PRINTF (1, 2)
+debug_agent_printf (const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!debug_agent)
+ return;
+ va_start (ap, fmt);
+ debug_vprintf (fmt, ap);
+ va_end (ap);
+}
+
+#define DEBUG_AGENT debug_agent_printf
+
+/* Global flag to determine using agent or not. */
+int use_agent = 0;
/* Addresses of in-process agent's symbols both GDB and GDBserver cares
about. */
-struct ipa_sym_addresses
+struct ipa_sym_addresses_common
{
CORE_ADDR addr_helper_thread_id;
CORE_ADDR addr_cmd_buf;
+ CORE_ADDR addr_capability;
};
/* Cache of the helper thread id. FIXME: this global should be made
per-process. */
-static unsigned int helper_thread_id = 0;
+static uint32_t helper_thread_id = 0;
static struct
{
const char *name;
int offset;
- int required;
} symbol_list[] = {
IPA_SYM(helper_thread_id),
IPA_SYM(cmd_buf),
+ IPA_SYM(capability),
};
-static struct ipa_sym_addresses ipa_sym_addrs;
+static struct ipa_sym_addresses_common ipa_sym_addrs;
+
+static int all_agent_symbols_looked_up = 0;
+
+int
+agent_loaded_p (void)
+{
+ return all_agent_symbols_looked_up;
+}
/* Look up all symbols needed by agent. Return 0 if all the symbols are
found, return non-zero otherwise. */
int
-agent_look_up_symbols (void)
+agent_look_up_symbols (void *arg)
{
int i;
+ all_agent_symbols_looked_up = 0;
+
for (i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++)
{
CORE_ADDR *addrp =
(CORE_ADDR *) ((char *) &ipa_sym_addrs + symbol_list[i].offset);
-#ifdef GDBSERVER
-
- if (look_up_one_symbol (symbol_list[i].name, addrp, 1) == 0)
-#else
- struct minimal_symbol *sym = lookup_minimal_symbol (symbol_list[i].name,
- NULL, NULL);
+ struct objfile *objfile = (struct objfile *) arg;
- if (sym != NULL)
- *addrp = SYMBOL_VALUE_ADDRESS (sym);
- else
-#endif
+ if (find_minimal_symbol_address (symbol_list[i].name, addrp,
+ objfile) != 0)
{
DEBUG_AGENT ("symbol `%s' not found\n", symbol_list[i].name);
return -1;
}
}
+ all_agent_symbols_looked_up = 1;
return 0;
}
{
if (helper_thread_id == 0)
{
-#ifdef GDBSERVER
- if (read_inferior_memory (ipa_sym_addrs.addr_helper_thread_id,
- (unsigned char *) &helper_thread_id,
- sizeof helper_thread_id))
-#else
- enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
- gdb_byte buf[4];
-
- if (target_read_memory (ipa_sym_addrs.addr_helper_thread_id,
- buf, sizeof buf) == 0)
- helper_thread_id = extract_unsigned_integer (buf, sizeof buf,
- byte_order);
- else
-#endif
- {
- warning ("Error reading helper thread's id in lib");
- }
+ if (target_read_uint32 (ipa_sym_addrs.addr_helper_thread_id,
+ &helper_thread_id))
+ warning (_("Error reading helper thread's id in lib"));
}
return helper_thread_id;
if (res >= UNIX_PATH_MAX)
return -1;
- res = fd = socket (PF_UNIX, SOCK_STREAM, 0);
+ res = fd = gdb_socket_cloexec (PF_UNIX, SOCK_STREAM, 0);
if (res == -1)
{
- warning ("error opening sync socket: %s\n", strerror (errno));
+ warning (_("error opening sync socket: %s"), strerror (errno));
return -1;
}
res = xsnprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path);
if (res >= UNIX_PATH_MAX)
{
- warning ("string overflow allocating socket name\n");
+ warning (_("string overflow allocating socket name"));
close (fd);
return -1;
}
res = connect (fd, (struct sockaddr *) &addr, sizeof (addr));
if (res == -1)
{
- warning ("error connecting sync socket (%s): %s. "
- "Make sure the directory exists and that it is writable.",
- path, strerror (errno));
+ warning (_("error connecting sync socket (%s): %s. "
+ "Make sure the directory exists and that it is writable."),
+ path, strerror (errno));
close (fd);
return -1;
}
socket. Return zero if success, otherwise return non-zero. */
int
-agent_run_command (int pid, const char *cmd)
+agent_run_command (int pid, const char *cmd, int len)
{
int fd;
int tid = agent_get_helper_thread_id ();
- ptid_t ptid = ptid_build (pid, tid, 0);
- int len = strlen (cmd) + 1;
+ ptid_t ptid = ptid_t (pid, tid, 0);
-#ifdef GDBSERVER
- int ret = write_inferior_memory (ipa_sym_addrs.addr_cmd_buf,
- (const unsigned char *) cmd, len);
-#else
- int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf, cmd, len);
-#endif
+ int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf,
+ (gdb_byte *) cmd, len);
if (ret != 0)
{
- warning ("unable to write");
+ warning (_("unable to write"));
return -1;
}
DEBUG_AGENT ("agent: resumed helper thread\n");
/* Resume helper thread. */
-#ifdef GDBSERVER
-{
- struct thread_resume resume_info;
-
- resume_info.thread = ptid;
- resume_info.kind = resume_continue;
- resume_info.sig = TARGET_SIGNAL_0;
- (*the_target->resume) (&resume_info, 1);
-}
-#else
- target_resume (ptid, 0, TARGET_SIGNAL_0);
-#endif
+ target_continue_no_signal (ptid);
fd = gdb_connect_sync_socket (pid);
if (fd >= 0)
{
char buf[1] = "";
- int ret;
DEBUG_AGENT ("agent: signalling helper thread\n");
return -1;
/* Need to read response with the inferior stopped. */
- if (!ptid_equal (ptid, null_ptid))
+ if (ptid != null_ptid)
{
- struct target_waitstatus status;
- int was_non_stop = non_stop;
/* Stop thread PTID. */
DEBUG_AGENT ("agent: stop helper thread\n");
-#ifdef GDBSERVER
- {
- struct thread_resume resume_info;
-
- resume_info.thread = ptid;
- resume_info.kind = resume_stop;
- resume_info.sig = TARGET_SIGNAL_0;
- (*the_target->resume) (&resume_info, 1);
- }
-
- non_stop = 1;
- mywait (ptid, &status, 0, 0);
-#else
- non_stop = 1;
- target_stop (ptid);
-
- memset (&status, 0, sizeof (status));
- target_wait (ptid, &status, 0);
-#endif
- non_stop = was_non_stop;
+ target_stop_and_wait (ptid);
}
if (fd >= 0)
{
-#ifdef GDBSERVER
- if (read_inferior_memory (ipa_sym_addrs.addr_cmd_buf,
- (unsigned char *) cmd, IPA_CMD_BUF_SIZE))
-#else
if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd,
IPA_CMD_BUF_SIZE))
-#endif
{
- warning ("Error reading command response");
+ warning (_("Error reading command response"));
return -1;
}
}
return 0;
}
+
+/* Each bit of it stands for a capability of agent. */
+static uint32_t agent_capability = 0;
+
+/* Return true if agent has capability AGENT_CAP, otherwise return false. */
+
+int
+agent_capability_check (enum agent_capa agent_capa)
+{
+ if (agent_capability == 0)
+ {
+ if (target_read_uint32 (ipa_sym_addrs.addr_capability,
+ &agent_capability))
+ warning (_("Error reading capability of agent"));
+ }
+ return agent_capability & agent_capa;
+}
+
+/* Invalidate the cache of agent capability, so we'll read it from inferior
+ again. Call it when launches a new program or reconnect to remote stub. */
+
+void
+agent_capability_invalidate (void)
+{
+ agent_capability = 0;
+}