/* Tracepoint code for remote server for GDB.
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Copyright (C) 2009-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "server.h"
#include "tracepoint.h"
#include "gdbthread.h"
-#include "agent.h"
-#include "rsp-low.h"
+#include "gdbsupport/rsp-low.h"
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
-#include "gdb_sys_time.h"
+#include <chrono>
#include <inttypes.h>
#include "ax.h"
#include "tdesc.h"
+#define IPA_SYM_STRUCT_NAME ipa_sym_addresses
+#include "gdbsupport/agent.h"
+
#define DEFAULT_TRACE_BUFFER_SIZE 5242880 /* 5*1024*1024 */
/* This file is built for both GDBserver, and the in-process
# define gdb_trampoline_buffer_end IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_end)
# define gdb_trampoline_buffer_error IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_error)
# define collecting IPA_SYM_EXPORTED_NAME (collecting)
-# define gdb_collect IPA_SYM_EXPORTED_NAME (gdb_collect)
+# define gdb_collect_ptr IPA_SYM_EXPORTED_NAME (gdb_collect_ptr)
# define stop_tracing IPA_SYM_EXPORTED_NAME (stop_tracing)
# define flush_trace_buffer IPA_SYM_EXPORTED_NAME (flush_trace_buffer)
# define about_to_request_buffer_space IPA_SYM_EXPORTED_NAME (about_to_request_buffer_space)
# define traceframe_write_count IPA_SYM_EXPORTED_NAME (traceframe_write_count)
# define traceframes_created IPA_SYM_EXPORTED_NAME (traceframes_created)
# define trace_state_variables IPA_SYM_EXPORTED_NAME (trace_state_variables)
-# define get_raw_reg IPA_SYM_EXPORTED_NAME (get_raw_reg)
-# define get_trace_state_variable_value \
- IPA_SYM_EXPORTED_NAME (get_trace_state_variable_value)
-# define set_trace_state_variable_value \
- IPA_SYM_EXPORTED_NAME (set_trace_state_variable_value)
+# define get_raw_reg_ptr IPA_SYM_EXPORTED_NAME (get_raw_reg_ptr)
+# define get_trace_state_variable_value_ptr \
+ IPA_SYM_EXPORTED_NAME (get_trace_state_variable_value_ptr)
+# define set_trace_state_variable_value_ptr \
+ IPA_SYM_EXPORTED_NAME (set_trace_state_variable_value_ptr)
# define ust_loaded IPA_SYM_EXPORTED_NAME (ust_loaded)
# define helper_thread_id IPA_SYM_EXPORTED_NAME (helper_thread_id)
# define cmd_buf IPA_SYM_EXPORTED_NAME (cmd_buf)
+# define ipa_tdesc_idx IPA_SYM_EXPORTED_NAME (ipa_tdesc_idx)
#endif
#ifndef IN_PROCESS_AGENT
CORE_ADDR addr_gdb_trampoline_buffer_end;
CORE_ADDR addr_gdb_trampoline_buffer_error;
CORE_ADDR addr_collecting;
- CORE_ADDR addr_gdb_collect;
+ CORE_ADDR addr_gdb_collect_ptr;
CORE_ADDR addr_stop_tracing;
CORE_ADDR addr_flush_trace_buffer;
CORE_ADDR addr_about_to_request_buffer_space;
CORE_ADDR addr_traceframe_write_count;
CORE_ADDR addr_traceframes_created;
CORE_ADDR addr_trace_state_variables;
- CORE_ADDR addr_get_raw_reg;
- CORE_ADDR addr_get_trace_state_variable_value;
- CORE_ADDR addr_set_trace_state_variable_value;
+ CORE_ADDR addr_get_raw_reg_ptr;
+ CORE_ADDR addr_get_trace_state_variable_value_ptr;
+ CORE_ADDR addr_set_trace_state_variable_value_ptr;
CORE_ADDR addr_ust_loaded;
+ CORE_ADDR addr_ipa_tdesc_idx;
};
static struct
IPA_SYM(gdb_trampoline_buffer_end),
IPA_SYM(gdb_trampoline_buffer_error),
IPA_SYM(collecting),
- IPA_SYM(gdb_collect),
+ IPA_SYM(gdb_collect_ptr),
IPA_SYM(stop_tracing),
IPA_SYM(flush_trace_buffer),
IPA_SYM(about_to_request_buffer_space),
IPA_SYM(traceframe_write_count),
IPA_SYM(traceframes_created),
IPA_SYM(trace_state_variables),
- IPA_SYM(get_raw_reg),
- IPA_SYM(get_trace_state_variable_value),
- IPA_SYM(set_trace_state_variable_value),
+ IPA_SYM(get_raw_reg_ptr),
+ IPA_SYM(get_trace_state_variable_value_ptr),
+ IPA_SYM(set_trace_state_variable_value_ptr),
IPA_SYM(ust_loaded),
+ IPA_SYM(ipa_tdesc_idx),
};
static struct ipa_sym_addresses ipa_sym_addrs;
write_inferior_data_pointer (CORE_ADDR symaddr, CORE_ADDR val)
{
void *pval = (void *) (uintptr_t) val;
- return write_inferior_memory (symaddr,
+ return target_write_memory (symaddr,
(unsigned char *) &pval, sizeof (pval));
}
static int
write_inferior_integer (CORE_ADDR symaddr, int val)
{
- return write_inferior_memory (symaddr, (unsigned char *) &val, sizeof (val));
+ return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val));
+}
+
+static int
+write_inferior_int8 (CORE_ADDR symaddr, int8_t val)
+{
+ return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val));
}
static int
write_inferior_uinteger (CORE_ADDR symaddr, unsigned int val)
{
- return write_inferior_memory (symaddr, (unsigned char *) &val, sizeof (val));
+ return target_write_memory (symaddr, (unsigned char *) &val, sizeof (val));
}
static CORE_ADDR target_malloc (ULONGEST size);
-static int write_inferior_data_ptr (CORE_ADDR where, CORE_ADDR ptr);
#define COPY_FIELD_TO_BUF(BUF, OBJ, FIELD) \
do { \
#endif
-/* Operations on various types of tracepoint actions. */
-
-struct tracepoint_action;
-
-struct tracepoint_action_ops
-{
- /* Download tracepoint action ACTION to IPA. Return the address of action
- in IPA/inferior. */
- CORE_ADDR (*download) (const struct tracepoint_action *action);
-
- /* Send ACTION to agent via command buffer started from BUFFER. Return
- updated head of command buffer. */
- char* (*send) (char *buffer, const struct tracepoint_action *action);
-};
-
/* Base action. Concrete actions inherit this. */
struct tracepoint_action
{
-#ifndef IN_PROCESS_AGENT
- const struct tracepoint_action_ops *ops;
-#endif
char type;
};
static CORE_ADDR
m_tracepoint_action_download (const struct tracepoint_action *action)
{
- int size_in_ipa = (sizeof (struct collect_memory_action)
- - offsetof (struct tracepoint_action, type));
- CORE_ADDR ipa_action = target_malloc (size_in_ipa);
+ CORE_ADDR ipa_action = target_malloc (sizeof (struct collect_memory_action));
- write_inferior_memory (ipa_action, (unsigned char *) &action->type,
- size_in_ipa);
+ target_write_memory (ipa_action, (unsigned char *) action,
+ sizeof (struct collect_memory_action));
return ipa_action;
}
return buffer;
}
-static const struct tracepoint_action_ops m_tracepoint_action_ops =
-{
- m_tracepoint_action_download,
- m_tracepoint_action_send,
-};
-
static CORE_ADDR
r_tracepoint_action_download (const struct tracepoint_action *action)
{
- int size_in_ipa = (sizeof (struct collect_registers_action)
- - offsetof (struct tracepoint_action, type));
- CORE_ADDR ipa_action = target_malloc (size_in_ipa);
+ CORE_ADDR ipa_action = target_malloc (sizeof (struct collect_registers_action));
- write_inferior_memory (ipa_action, (unsigned char *) &action->type,
- size_in_ipa);
+ target_write_memory (ipa_action, (unsigned char *) action,
+ sizeof (struct collect_registers_action));
return ipa_action;
}
return buffer;
}
-static const struct tracepoint_action_ops r_tracepoint_action_ops =
-{
- r_tracepoint_action_download,
- r_tracepoint_action_send,
-};
-
static CORE_ADDR download_agent_expr (struct agent_expr *expr);
static CORE_ADDR
x_tracepoint_action_download (const struct tracepoint_action *action)
{
- int size_in_ipa = (sizeof (struct eval_expr_action)
- - offsetof (struct tracepoint_action, type));
- CORE_ADDR ipa_action = target_malloc (size_in_ipa);
+ CORE_ADDR ipa_action = target_malloc (sizeof (struct eval_expr_action));
CORE_ADDR expr;
- write_inferior_memory (ipa_action, (unsigned char *) &action->type,
- size_in_ipa);
- expr = download_agent_expr (((struct eval_expr_action *)action)->expr);
- write_inferior_data_ptr (ipa_action + offsetof (struct eval_expr_action, expr)
- - offsetof (struct tracepoint_action, type),
- expr);
+ target_write_memory (ipa_action, (unsigned char *) action,
+ sizeof (struct eval_expr_action));
+ expr = download_agent_expr (((struct eval_expr_action *) action)->expr);
+ write_inferior_data_pointer (ipa_action
+ + offsetof (struct eval_expr_action, expr),
+ expr);
return ipa_action;
}
return agent_expr_send (buffer, eaction->expr);
}
-static const struct tracepoint_action_ops x_tracepoint_action_ops =
-{
- x_tracepoint_action_download,
- x_tracepoint_action_send,
-};
-
static CORE_ADDR
l_tracepoint_action_download (const struct tracepoint_action *action)
{
- int size_in_ipa = (sizeof (struct collect_static_trace_data_action)
- - offsetof (struct tracepoint_action, type));
- CORE_ADDR ipa_action = target_malloc (size_in_ipa);
+ CORE_ADDR ipa_action
+ = target_malloc (sizeof (struct collect_static_trace_data_action));
- write_inferior_memory (ipa_action, (unsigned char *) &action->type,
- size_in_ipa);
+ target_write_memory (ipa_action, (unsigned char *) action,
+ sizeof (struct collect_static_trace_data_action));
return ipa_action;
}
return buffer;
}
-static const struct tracepoint_action_ops l_tracepoint_action_ops =
+static char *
+tracepoint_action_send (char *buffer, const struct tracepoint_action *action)
{
- l_tracepoint_action_download,
- l_tracepoint_action_send,
-};
+ switch (action->type)
+ {
+ case 'M':
+ return m_tracepoint_action_send (buffer, action);
+ case 'R':
+ return r_tracepoint_action_send (buffer, action);
+ case 'X':
+ return x_tracepoint_action_send (buffer, action);
+ case 'L':
+ return l_tracepoint_action_send (buffer, action);
+ }
+ error ("Unknown trace action '%c'.", action->type);
+}
+
+static CORE_ADDR
+tracepoint_action_download (const struct tracepoint_action *action)
+{
+ switch (action->type)
+ {
+ case 'M':
+ return m_tracepoint_action_download (action);
+ case 'R':
+ return r_tracepoint_action_download (action);
+ case 'X':
+ return x_tracepoint_action_download (action);
+ case 'L':
+ return l_tracepoint_action_download (action);
+ }
+ error ("Unknown trace action '%c'.", action->type);
+}
#endif
/* This structure describes a piece of the source-level definition of
fields (and no data) marks the end of trace data. */
#define TRACEFRAME_EOB_MARKER_SIZE offsetof (struct traceframe, data)
-/* The traceframe to be used as the source of data to send back to
- GDB. A value of -1 means to get data from the live program. */
-
-int current_traceframe = -1;
-
/* This flag is true if the trace buffer is circular, meaning that
when it fills, the oldest trace frames are discarded in order to
make room. */
/* Control structure holding the read/write/etc. pointers into the
trace buffer. We need more than one of these to implement a
- transaction-like mechanism to garantees that both GDBserver and the
+ transaction-like mechanism to guarantees that both GDBserver and the
in-process agent can try to change the trace buffer
simultaneously. */
ipa_trace_buffer_ctrl.wrap = ipa_trace_buffer_hi;
/* A traceframe with zeroed fields marks the end of trace data. */
- write_inferior_memory (ipa_sym_addrs.addr_trace_buffer_ctrl,
+ target_write_memory (ipa_sym_addrs.addr_trace_buffer_ctrl,
(unsigned char *) &ipa_trace_buffer_ctrl,
sizeof (ipa_trace_buffer_ctrl));
write_inferior_uinteger (ipa_sym_addrs.addr_trace_buffer_ctrl_curr, 0);
/* A traceframe with zeroed fields marks the end of trace data. */
- write_inferior_memory (ipa_trace_buffer_lo,
+ target_write_memory (ipa_trace_buffer_lo,
(unsigned char *) &ipa_traceframe,
sizeof (ipa_traceframe));
/* Append another action to perform when the tracepoint triggers. */
static void
-add_tracepoint_action (struct tracepoint *tpoint, char *packet)
+add_tracepoint_action (struct tracepoint *tpoint, const char *packet)
{
- char *act;
+ const char *act;
if (*packet == 'S')
{
while (*act)
{
- char *act_start = act;
+ const char *act_start = act;
struct tracepoint_action *action = NULL;
switch (*act)
int is_neg;
maction->base.type = *act;
- maction->base.ops = &m_tracepoint_action_ops;
action = &maction->base;
++act;
XNEW (struct collect_registers_action);
raction->base.type = *act;
- raction->base.ops = &r_tracepoint_action_ops;
action = &raction->base;
trace_debug ("Want to collect registers");
XNEW (struct collect_static_trace_data_action);
raction->base.type = *act;
- raction->base.ops = &l_tracepoint_action_ops;
action = &raction->base;
trace_debug ("Want to collect static trace data");
struct eval_expr_action *xaction = XNEW (struct eval_expr_action);
xaction->base.type = *act;
- xaction->base.ops = &x_tracepoint_action_ops;
action = &xaction->base;
trace_debug ("Want to evaluate expression");
find_next_traceframe_in_range (CORE_ADDR lo, CORE_ADDR hi, int inside_p,
int *tfnump)
{
+ client_state &cs = get_client_state ();
struct traceframe *tframe;
CORE_ADDR tfaddr;
- *tfnump = current_traceframe + 1;
+ *tfnump = cs.current_traceframe + 1;
tframe = find_traceframe (*tfnump);
/* The search is not supposed to wrap around. */
if (!tframe)
static struct traceframe *
find_next_traceframe_by_tracepoint (int num, int *tfnump)
{
+ client_state &cs = get_client_state ();
struct traceframe *tframe;
- *tfnump = current_traceframe + 1;
+ *tfnump = cs.current_traceframe + 1;
tframe = find_traceframe (*tfnump);
/* The search is not supposed to wrap around. */
if (!tframe)
static void
cmd_qtinit (char *packet)
{
+ client_state &cs = get_client_state ();
struct trace_state_variable *tsv, *prev, *next;
/* Can't do this command without a pid attached. */
}
/* Make sure we don't try to read from a trace frame. */
- current_traceframe = -1;
+ cs.current_traceframe = -1;
stop_tracing ();
switch (tpoint->type)
{
case trap_tracepoint:
- delete_breakpoint (tpoint->handle);
+ {
+ struct breakpoint *bp
+ = (struct breakpoint *) tpoint->handle;
+
+ delete_breakpoint (bp);
+ }
break;
case fast_tracepoint:
- delete_fast_tracepoint_jump (tpoint->handle);
+ {
+ struct fast_tracepoint_jump *jump
+ = (struct fast_tracepoint_jump *) tpoint->handle;
+
+ delete_fast_tracepoint_jump (jump);
+ }
break;
case static_tracepoint:
if (prev_stpoint != NULL
ULONGEST addr;
ULONGEST count;
struct tracepoint *tpoint;
- char *actparm;
- char *packet = own_buf;
+ const char *packet = own_buf;
packet += strlen ("QTDP:");
}
else if (*packet == 'X')
{
- actparm = (char *) packet;
- tpoint->cond = gdb_parse_agent_expr (&actparm);
- packet = actparm;
+ tpoint->cond = gdb_parse_agent_expr (&packet);
}
else if (*packet == '-')
break;
{
ULONGEST num, addr, start, slen;
struct tracepoint *tpoint;
- char *packet = own_buf;
- char *saved, *srctype, *src;
+ const char *packet = own_buf;
+ const char *saved;
+ char *srctype, *src;
size_t nbytes;
struct source_string *last, *newlast;
char *varname;
size_t nbytes;
struct trace_state_variable *tsv;
- char *packet = own_buf;
+ const char *packet = own_buf;
packet += strlen ("QTDV:");
static void
cmd_qtenable_disable (char *own_buf, int enable)
{
- char *packet = own_buf;
+ const char *packet = own_buf;
ULONGEST num, addr;
struct tracepoint *tp;
write_enn (own_buf);
return;
}
-
- ret = write_inferior_integer (obj_addr, enable);
+
+ ret = write_inferior_int8 (obj_addr, enable);
done_accessing_memory ();
if (ret)
static void
cmd_qtv (char *own_buf)
{
+ client_state &cs = get_client_state ();
ULONGEST num;
LONGEST val = 0;
int err;
packet += strlen ("qTV:");
unpack_varlen_hex (packet, &num);
- if (current_traceframe >= 0)
+ if (cs.current_traceframe >= 0)
{
err = traceframe_read_tsv ((int) num, &val);
if (err)
{
ULONGEST start, end;
struct readonly_region *roreg;
- char *packet = own_buf;
+ const char *packet = own_buf;
trace_debug ("Want to mark readonly regions");
{
CORE_ADDR jentry, jump_entry;
CORE_ADDR trampoline;
+ CORE_ADDR collect;
ULONGEST trampoline_size;
int err = 0;
/* The jump to the jump pad of the last fast tracepoint
return 0;
}
+ if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_collect_ptr,
+ &collect))
+ {
+ error ("error extracting gdb_collect_ptr");
+ return 1;
+ }
+
jentry = jump_entry = get_jump_space_head ();
trampoline = 0;
/* Install the jump pad. */
err = install_fast_tracepoint_jump_pad (tpoint->obj_addr_on_target,
tpoint->address,
- ipa_sym_addrs.addr_gdb_collect,
+ collect,
ipa_sym_addrs.addr_collecting,
tpoint->orig_size,
&jentry,
*packet = '\0';
+ if (agent_loaded_p ())
+ {
+ /* Tell IPA about the correct tdesc. */
+ if (write_inferior_integer (ipa_sym_addrs.addr_ipa_tdesc_idx,
+ target_get_ipa_tdesc_idx ()))
+ error ("Error setting ipa_tdesc_idx variable in lib");
+ }
+
/* Start out empty. */
if (agent_loaded_p ())
- write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, 0);
+ write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, 0);
/* Download and install tracepoints. */
for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
if (tpoint == tracepoints)
/* First object in list, set the head pointer in the
inferior. */
- write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, tpptr);
+ write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints, tpptr);
else
- write_inferior_data_ptr (prev_tpptr + offsetof (struct tracepoint,
- next),
- tpptr);
+ write_inferior_data_pointer (prev_tpptr
+ + offsetof (struct tracepoint, next),
+ tpptr);
}
/* Any failure in the inner loop is sufficient cause to give
static void
cmd_qtframe (char *own_buf)
{
+ client_state &cs = get_client_state ();
ULONGEST frame, pc, lo, hi, num;
int tfnum, tpnum;
struct traceframe *tframe;
- char *packet = own_buf;
+ const char *packet = own_buf;
packet += strlen ("QTFrame:");
if (tfnum == -1)
{
trace_debug ("Want to stop looking at traceframes");
- current_traceframe = -1;
+ cs.current_traceframe = -1;
write_ok (own_buf);
return;
}
if (tframe)
{
- current_traceframe = tfnum;
+ cs.current_traceframe = tfnum;
sprintf (own_buf, "F%xT%x", tfnum, tframe->tpnum);
}
else
{
ULONGEST num, addr;
struct tracepoint *tpoint;
- char *packet = own_buf;
+ const char *packet = own_buf;
packet += strlen ("qTP:");
run_inferior_command (packet, strlen (packet) + 1);
}
-/* Helper for gdb_agent_about_to_close.
- Return non-zero if thread ENTRY is in the same process in DATA. */
-
-static int
-same_process_p (struct inferior_list_entry *entry, void *data)
-{
- int *pid = (int *) data;
-
- return ptid_get_pid (entry->id) == *pid;
-}
-
/* Sent the agent a command to close it. */
void
saved_thread = current_thread;
/* Find any thread which belongs to process PID. */
- current_thread = (struct thread_info *)
- find_inferior (&all_threads, same_process_p, &pid);
+ current_thread = find_any_thread_of_pid (pid);
strcpy (buf, "close");
{
ULONGEST offset, num, tot;
unsigned char *tbp;
- char *packet = own_buf;
+ const char *packet = own_buf;
packet += strlen ("qTBuffer:");
wstep_link = &tinfo->while_stepping;
trace_debug ("Thread %s finished a single-step for tracepoint %d at 0x%s",
- target_pid_to_str (tinfo->entry.id),
+ target_pid_to_str (tinfo->id),
wstep->tp_number, paddress (wstep->tp_address));
ctx.base.type = trap_tracepoint;
{
trace_debug ("NO TRACEPOINT %d at 0x%s FOR THREAD %s!",
wstep->tp_number, paddress (wstep->tp_address),
- target_pid_to_str (tinfo->entry.id));
+ target_pid_to_str (tinfo->id));
/* Unlink. */
*wstep_link = wstep->next;
{
/* The requested numbers of steps have occurred. */
trace_debug ("Thread %s done stepping for tracepoint %d at 0x%s",
- target_pid_to_str (tinfo->entry.id),
+ target_pid_to_str (tinfo->id),
wstep->tp_number, paddress (wstep->tp_address));
/* Unlink the wstep. */
trace_debug ("lib stopped due to full buffer.");
if (ipa_stopping_tracepoint)
trace_debug ("lib stopped due to tpoint");
- if (ipa_stopping_tracepoint)
+ if (ipa_error_tracepoint)
trace_debug ("lib stopped due to error");
}
&& tpoint->type != static_tracepoint)
{
trace_debug ("Thread %s at address of tracepoint %d at 0x%s",
- target_pid_to_str (tinfo->entry.id),
+ target_pid_to_str (tinfo->id),
tpoint->number, paddress (tpoint->address));
/* Test the condition if present, and collect if true. */
#endif
#ifdef IN_PROCESS_AGENT
-/* The target description used by the IPA. Given that the IPA library
- is built for a specific architecture that is loaded into the
- inferior, there only needs to be one such description per
- build. */
-const struct target_desc *ipa_tdesc;
+/* The target description index for IPA. Passed from gdbserver, used
+ to select ipa_tdesc. */
+EXTERN_C_PUSH
+IP_AGENT_EXPORT_VAR int ipa_tdesc_idx;
+EXTERN_C_POP
#endif
static struct regcache *
get_context_regcache (struct tracepoint_hit_ctx *ctx)
{
struct regcache *regcache = NULL;
-
#ifdef IN_PROCESS_AGENT
+ const struct target_desc *ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
+
if (ctx->type == fast_tracepoint)
{
struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx;
return NULL;
}
-/* Look for the block of type TYPE_WANTED in the trameframe starting
+/* Look for the block of type TYPE_WANTED in the traceframe starting
at DATABASE of DATASIZE bytes long. TFNUM is the traceframe
number. */
static int
traceframe_read_tsv (int tsvnum, LONGEST *val)
{
+ client_state &cs = get_client_state ();
int tfnum;
struct traceframe *tframe;
unsigned char *database, *dataptr;
trace_debug ("traceframe_read_tsv");
- tfnum = current_traceframe;
+ tfnum = cs.current_traceframe;
if (tfnum < 0)
{
case, if we want to move the thread out of the jump pad, we need to
single-step it until this function returns 0. */
-int
+fast_tpoint_collect_result
fast_tracepoint_collecting (CORE_ADDR thread_area,
CORE_ADDR stop_pc,
struct fast_tpoint_collect_status *status)
if (tpoint == NULL)
{
warning ("in jump pad, but no matching tpoint?");
- return 0;
+ return fast_tpoint_collect_result::not_collecting;
}
else
{
if (tpoint == NULL)
{
warning ("in trampoline, but no matching tpoint?");
- return 0;
+ return fast_tpoint_collect_result::not_collecting;
}
else
{
{
trace_debug ("fast_tracepoint_collecting:"
" failed reading 'collecting' in the inferior");
- return 0;
+ return fast_tpoint_collect_result::not_collecting;
}
if (!ipa_collecting)
{
trace_debug ("fast_tracepoint_collecting: not collecting"
" (and nobody is).");
- return 0;
+ return fast_tpoint_collect_result::not_collecting;
}
/* Some thread is collecting. Check which. */
{
trace_debug ("fast_tracepoint_collecting: not collecting "
"(another thread is)");
- return 0;
+ return fast_tpoint_collect_result::not_collecting;
}
tpoint
warning ("fast_tracepoint_collecting: collecting, "
"but tpoint %s not found?",
paddress ((CORE_ADDR) ipa_collecting_obj.tpoint));
- return 0;
+ return fast_tpoint_collect_result::not_collecting;
}
/* The thread is within `gdb_collect', skip over the rest of
fast_tracepoint_collecting, returning continue-until-break at %s",
paddress (tpoint->adjusted_insn_addr));
- return 1; /* continue */
+ return fast_tpoint_collect_result::before_insn; /* continue */
}
else
{
paddress (tpoint->adjusted_insn_addr),
paddress (tpoint->adjusted_insn_addr_end));
- return 2; /* single-step */
+ return fast_tpoint_collect_result::at_insn; /* single-step */
}
}
gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
{
struct fast_tracepoint_ctx ctx;
+ const struct target_desc *ipa_tdesc;
/* Don't do anything until the trace run is completely set up. */
if (!tracing)
return;
+ ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
ctx.base.type = fast_tracepoint;
ctx.regs = regs;
ctx.regcache_initted = 0;
}
}
+/* These global variables points to the corresponding functions. This is
+ necessary on powerpc64, where asking for function symbol address from gdb
+ results in returning the actual code pointer, instead of the descriptor
+ pointer. */
+
+typedef void (*gdb_collect_ptr_type) (struct tracepoint *, unsigned char *);
+typedef ULONGEST (*get_raw_reg_ptr_type) (const unsigned char *, int);
+typedef LONGEST (*get_trace_state_variable_value_ptr_type) (int);
+typedef void (*set_trace_state_variable_value_ptr_type) (int, LONGEST);
+
+EXTERN_C_PUSH
+IP_AGENT_EXPORT_VAR gdb_collect_ptr_type gdb_collect_ptr = gdb_collect;
+IP_AGENT_EXPORT_VAR get_raw_reg_ptr_type get_raw_reg_ptr = get_raw_reg;
+IP_AGENT_EXPORT_VAR get_trace_state_variable_value_ptr_type
+ get_trace_state_variable_value_ptr = get_trace_state_variable_value;
+IP_AGENT_EXPORT_VAR set_trace_state_variable_value_ptr_type
+ set_trace_state_variable_value_ptr = set_trace_state_variable_value;
+EXTERN_C_POP
+
#endif
#ifndef IN_PROCESS_AGENT
CORE_ADDR
get_raw_reg_func_addr (void)
{
- return ipa_sym_addrs.addr_get_raw_reg;
+ CORE_ADDR res;
+ if (read_inferior_data_pointer (ipa_sym_addrs.addr_get_raw_reg_ptr, &res))
+ {
+ error ("error extracting get_raw_reg_ptr");
+ return 0;
+ }
+ return res;
}
CORE_ADDR
get_get_tsv_func_addr (void)
{
- return ipa_sym_addrs.addr_get_trace_state_variable_value;
+ CORE_ADDR res;
+ if (read_inferior_data_pointer (
+ ipa_sym_addrs.addr_get_trace_state_variable_value_ptr, &res))
+ {
+ error ("error extracting get_trace_state_variable_value_ptr");
+ return 0;
+ }
+ return res;
}
CORE_ADDR
get_set_tsv_func_addr (void)
{
- return ipa_sym_addrs.addr_set_trace_state_variable_value;
+ CORE_ADDR res;
+ if (read_inferior_data_pointer (
+ ipa_sym_addrs.addr_set_trace_state_variable_value_ptr, &res))
+ {
+ error ("error extracting set_trace_state_variable_value_ptr");
+ return 0;
+ }
+ return res;
}
static void
*jump_entry += 16;
}
-/* We'll need to adjust these when we consider bi-arch setups, and big
- endian machines. */
-
-static int
-write_inferior_data_ptr (CORE_ADDR where, CORE_ADDR ptr)
-{
- return write_inferior_memory (where,
- (unsigned char *) &ptr, sizeof (void *));
-}
-
/* The base pointer of the IPA's heap. This is the only memory the
IPA is allowed to use. The IPA should _not_ call the inferior's
`malloc' during operation. That'd be slow, and, most importantly,
CORE_ADDR expr_bytes;
expr_addr = target_malloc (sizeof (*expr));
- write_inferior_memory (expr_addr, (unsigned char *) expr, sizeof (*expr));
+ target_write_memory (expr_addr, (unsigned char *) expr, sizeof (*expr));
expr_bytes = target_malloc (expr->length);
- write_inferior_data_ptr (expr_addr + offsetof (struct agent_expr, bytes),
- expr_bytes);
- write_inferior_memory (expr_bytes, expr->bytes, expr->length);
+ write_inferior_data_pointer (expr_addr + offsetof (struct agent_expr, bytes),
+ expr_bytes);
+ target_write_memory (expr_bytes, expr->bytes, expr->length);
return expr_addr;
}
tracepoints before clearing our own copy. */
target_tracepoint.hit_count = 0;
- write_inferior_memory (tpptr, (unsigned char *) &target_tracepoint,
+ target_write_memory (tpptr, (unsigned char *) &target_tracepoint,
sizeof (target_tracepoint));
if (tpoint->cond)
- write_inferior_data_ptr (tpptr + offsetof (struct tracepoint,
- cond),
- download_agent_expr (tpoint->cond));
+ write_inferior_data_pointer (tpptr
+ + offsetof (struct tracepoint, cond),
+ download_agent_expr (tpoint->cond));
if (tpoint->numactions)
{
/* The pointers array. */
actions_array
= target_malloc (sizeof (*tpoint->actions) * tpoint->numactions);
- write_inferior_data_ptr (tpptr + offsetof (struct tracepoint,
- actions),
- actions_array);
+ write_inferior_data_pointer (tpptr + offsetof (struct tracepoint,
+ actions),
+ actions_array);
/* Now for each pointer, download the action. */
for (i = 0; i < tpoint->numactions; i++)
{
struct tracepoint_action *action = tpoint->actions[i];
- CORE_ADDR ipa_action = action->ops->download (action);
+ CORE_ADDR ipa_action = tracepoint_action_download (action);
if (ipa_action != 0)
- write_inferior_data_ptr
- (actions_array + i * sizeof (*tpoint->actions),
- ipa_action);
+ write_inferior_data_pointer (actions_array
+ + i * sizeof (*tpoint->actions),
+ ipa_action);
}
}
}
struct tracepoint_action *action = tpoint->actions[i];
p[0] = action->type;
- p = action->ops->send (&p[1], action);
+ p = tracepoint_action_send (&p[1], action);
}
get_jump_space_head ();
}
/* tpoint->next = tp_prev->next */
- write_inferior_data_ptr (tpoint->obj_addr_on_target
- + offsetof (struct tracepoint, next),
- tp_prev_target_next_addr);
+ write_inferior_data_pointer (tpoint->obj_addr_on_target
+ + offsetof (struct tracepoint, next),
+ tp_prev_target_next_addr);
/* tp_prev->next = tpoint */
- write_inferior_data_ptr (tp_prev->obj_addr_on_target
- + offsetof (struct tracepoint, next),
- tpoint->obj_addr_on_target);
+ write_inferior_data_pointer (tp_prev->obj_addr_on_target
+ + offsetof (struct tracepoint, next),
+ tpoint->obj_addr_on_target);
}
else
/* First object in list, set the head pointer in the
inferior. */
- write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints,
- tpoint->obj_addr_on_target);
+ write_inferior_data_pointer (ipa_sym_addrs.addr_tracepoints,
+ tpoint->obj_addr_on_target);
}
struct trace_state_variable *tsv;
/* Start out empty. */
- write_inferior_data_ptr (ipa_sym_addrs.addr_trace_state_variables, 0);
+ write_inferior_data_pointer (ipa_sym_addrs.addr_trace_state_variables, 0);
for (tsv = trace_state_variables; tsv != NULL; tsv = tsv->next)
{
/* First object in list, set the head pointer in the
inferior. */
- write_inferior_data_ptr (ipa_sym_addrs.addr_trace_state_variables,
- ptr);
+ write_inferior_data_pointer (ipa_sym_addrs.addr_trace_state_variables,
+ ptr);
}
else
{
- write_inferior_data_ptr (prev_ptr
- + offsetof (struct trace_state_variable,
- next),
- ptr);
+ write_inferior_data_pointer (prev_ptr
+ + offsetof (struct trace_state_variable,
+ next),
+ ptr);
}
/* Write the whole object. We'll fix up its pointers in a bit.
Assume no next, fixup when needed. */
target_tsv.next = NULL;
- write_inferior_memory (ptr, (unsigned char *) &target_tsv,
+ target_write_memory (ptr, (unsigned char *) &target_tsv,
sizeof (target_tsv));
if (tsv->name != NULL)
{
size_t size = strlen (tsv->name) + 1;
CORE_ADDR name_addr = target_malloc (size);
- write_inferior_memory (name_addr,
+ target_write_memory (name_addr,
(unsigned char *) tsv->name, size);
- write_inferior_data_ptr (ptr
- + offsetof (struct trace_state_variable,
- name),
- name_addr);
+ write_inferior_data_pointer (ptr
+ + offsetof (struct trace_state_variable,
+ name),
+ name_addr);
}
gdb_assert (tsv->getter == NULL);
if (prev_ptr != 0)
{
/* Fixup the next pointer in the last item in the list. */
- write_inferior_data_ptr (prev_ptr
- + offsetof (struct trace_state_variable,
- next), 0);
+ write_inferior_data_pointer (prev_ptr
+ + offsetof (struct trace_state_variable,
+ next), 0);
}
}
into GDBserver's trace buffer. This always uploads either all or
no trace frames. This is the counter part of
`trace_alloc_trace_buffer'. See its description of the atomic
- synching mechanism. */
+ syncing mechanism. */
static void
upload_fast_traceframes (void)
(int) (ipa_trace_buffer_hi - ipa_trace_buffer_lo));
}
- if (write_inferior_memory (ipa_trace_buffer_ctrl_addr,
+ if (target_write_memory (ipa_trace_buffer_ctrl_addr,
(unsigned char *) &ipa_trace_buffer_ctrl,
sizeof (struct ipa_trace_buffer_control)))
return;
{
struct tracepoint *tpoint;
struct static_tracepoint_ctx ctx;
+ const struct target_desc *ipa_tdesc;
/* Don't do anything until the trace run is completely set up. */
if (!tracing)
return;
}
+ ipa_tdesc = get_ipa_tdesc (ipa_tdesc_idx);
ctx.base.type = static_tracepoint;
ctx.regcache_initted = 0;
ctx.regs = regs;
run_inferior_command (char *cmd, int len)
{
int err = -1;
- int pid = ptid_get_pid (current_ptid);
+ int pid = current_ptid.pid ();
trace_debug ("run_inferior_command: running: %s", cmd);
result = fd = socket (PF_UNIX, SOCK_STREAM, 0);
if (result == -1)
{
- warning ("socket creation failed: %s", strerror (errno));
+ warning ("socket creation failed: %s", safe_strerror (errno));
return -1;
}
result = unlink (name);
if (result == -1)
{
- warning ("unlink failed: %s", strerror (errno));
+ warning ("unlink failed: %s", safe_strerror (errno));
close (fd);
return -1;
}
result = bind (fd, (struct sockaddr *) &addr, sizeof (addr));
if (result == -1)
{
- warning ("bind failed: %s", strerror (errno));
+ warning ("bind failed: %s", safe_strerror (errno));
close (fd);
return -1;
}
result = listen (fd, 1);
if (result == -1)
{
- warning ("listen: %s", strerror (errno));
+ warning ("listen: %s", safe_strerror (errno));
close (fd);
return -1;
}
if (listen_fd == -1)
{
- warning ("could not create sync socket\n");
+ warning ("could not create sync socket");
break;
}
if (fd < 0)
{
- warning ("Accept returned %d, error: %s\n",
- fd, strerror (errno));
+ warning ("Accept returned %d, error: %s",
+ fd, safe_strerror (errno));
break;
}
if (ret == -1)
{
warning ("reading socket (fd=%d) failed with %s",
- fd, strerror (errno));
+ fd, safe_strerror (errno));
close (fd);
break;
}
}
#include <sys/mman.h>
-#include <fcntl.h>
IP_AGENT_EXPORT_VAR char *gdb_tp_heap_buffer;
IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer;
gdb_agent_init ();
}
+#ifndef HAVE_GETAUXVAL
+/* Retrieve the value of TYPE from the auxiliary vector. If TYPE is not
+ found, 0 is returned. This function is provided if glibc is too old. */
+
+unsigned long
+getauxval (unsigned long type)
+{
+ unsigned long data[2];
+ FILE *f = fopen ("/proc/self/auxv", "r");
+ unsigned long value = 0;
+
+ if (f == NULL)
+ return 0;
+
+ while (fread (data, sizeof (data), 1, f) > 0)
+ {
+ if (data[0] == type)
+ {
+ value = data[1];
+ break;
+ }
+ }
+
+ fclose (f);
+ return value;
+}
+#endif
+
#endif /* IN_PROCESS_AGENT */
/* Return a timestamp, expressed as microseconds of the usual Unix
static LONGEST
get_timestamp (void)
{
- struct timeval tv;
+ using namespace std::chrono;
- if (gettimeofday (&tv, 0) != 0)
- return -1;
- else
- return (LONGEST) tv.tv_sec * 1000000 + tv.tv_usec;
+ steady_clock::time_point now = steady_clock::now ();
+ return duration_cast<microseconds> (now.time_since_epoch ()).count ();
}
void
#ifdef IN_PROCESS_AGENT
{
- uintptr_t addr;
int pagesize;
+ size_t jump_pad_size;
pagesize = sysconf (_SC_PAGE_SIZE);
if (pagesize == -1)
perror_with_name ("sysconf");
- gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
-
#define SCRATCH_BUFFER_NPAGES 20
- /* Allocate scratch buffer aligned on a page boundary, at a low
- address (close to the main executable's code). */
- for (addr = pagesize; addr != 0; addr += pagesize)
- {
- gdb_jump_pad_buffer
- = (char *) mmap ((void *) addr,
- pagesize * SCRATCH_BUFFER_NPAGES,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
- -1, 0);
- if (gdb_jump_pad_buffer != MAP_FAILED)
- break;
- }
+ jump_pad_size = pagesize * SCRATCH_BUFFER_NPAGES;
- if (addr == 0)
+ gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
+ gdb_jump_pad_buffer = (char *) alloc_jump_pad_buffer (jump_pad_size);
+ if (gdb_jump_pad_buffer == NULL)
perror_with_name ("mmap");
-
- gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + pagesize * SCRATCH_BUFFER_NPAGES;
+ gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + jump_pad_size;
}
gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0;