| Index: gdb/gdbserver/tracepoint.c
|
| diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
|
| index f103dfce81a8ffe54d468554deb43e19a195074b..ea1a8a106fa2efd41d127e3a99fd9004e560eeeb 100644
|
| --- a/gdb/gdbserver/tracepoint.c
|
| +++ b/gdb/gdbserver/tracepoint.c
|
| @@ -1,5 +1,5 @@
|
| /* Tracepoint code for remote server for GDB.
|
| - Copyright (C) 2009-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 2009-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -17,6 +17,7 @@
|
| along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
| #include "server.h"
|
| +#include "tracepoint.h"
|
| #include "gdbthread.h"
|
| #include "agent.h"
|
|
|
| @@ -29,6 +30,9 @@
|
| #include <stdint.h>
|
|
|
| #include "ax.h"
|
| +#include "tdesc.h"
|
| +
|
| +#define DEFAULT_TRACE_BUFFER_SIZE 5242880 /* 5*1024*1024 */
|
|
|
| /* This file is built for both GDBserver, and the in-process
|
| agent (IPA), a shared library that includes a tracing agent that is
|
| @@ -57,7 +61,7 @@
|
|
|
| */
|
|
|
| -static void trace_vdebug (const char *, ...) ATTR_FORMAT (printf, 1, 2);
|
| +static void trace_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2);
|
|
|
| static void
|
| trace_vdebug (const char *fmt, ...)
|
| @@ -979,6 +983,10 @@ struct traceframe
|
|
|
| } ATTR_PACKED;
|
|
|
| +/* The size of the EOB marker, in bytes. A traceframe with zeroed
|
| + 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. */
|
|
|
| @@ -992,6 +1000,10 @@ int current_traceframe = -1;
|
| static int circular_trace_buffer;
|
| #endif
|
|
|
| +/* Size of the trace buffer. */
|
| +
|
| +static LONGEST trace_buffer_size;
|
| +
|
| /* Pointer to the block of memory that traceframes all go into. */
|
|
|
| static unsigned char *trace_buffer_lo;
|
| @@ -1346,12 +1358,6 @@ struct trap_tracepoint_ctx
|
|
|
| #endif
|
|
|
| -static enum eval_result_type
|
| -eval_tracepoint_agent_expr (struct tracepoint_hit_ctx *ctx,
|
| - struct traceframe *tframe,
|
| - struct agent_expr *aexpr,
|
| - ULONGEST *rslt);
|
| -
|
| #ifndef IN_PROCESS_AGENT
|
| static CORE_ADDR traceframe_get_pc (struct traceframe *tframe);
|
| static int traceframe_read_tsv (int num, LONGEST *val);
|
| @@ -1484,10 +1490,19 @@ clear_inferior_trace_buffer (void)
|
| #endif
|
|
|
| static void
|
| -init_trace_buffer (unsigned char *buf, int bufsize)
|
| +init_trace_buffer (LONGEST bufsize)
|
| {
|
| - trace_buffer_lo = buf;
|
| - trace_buffer_hi = trace_buffer_lo + bufsize;
|
| + size_t alloc_size;
|
| +
|
| + trace_buffer_size = bufsize;
|
| +
|
| + /* Make sure to internally allocate at least space for the EOB
|
| + marker. */
|
| + alloc_size = (bufsize < TRACEFRAME_EOB_MARKER_SIZE
|
| + ? TRACEFRAME_EOB_MARKER_SIZE : bufsize);
|
| + trace_buffer_lo = xrealloc (trace_buffer_lo, alloc_size);
|
| +
|
| + trace_buffer_hi = trace_buffer_lo + trace_buffer_size;
|
|
|
| clear_trace_buffer ();
|
| }
|
| @@ -1527,7 +1542,7 @@ trace_buffer_alloc (size_t amt)
|
| (long) amt, (long) sizeof (struct traceframe));
|
|
|
| /* Account for the EOB marker. */
|
| - amt += sizeof (struct traceframe);
|
| + amt += TRACEFRAME_EOB_MARKER_SIZE;
|
|
|
| #ifdef IN_PROCESS_AGENT
|
| again:
|
| @@ -1902,18 +1917,6 @@ find_next_tracepoint_by_number (struct tracepoint *prev_tp, int num)
|
|
|
| #endif
|
|
|
| -static char *
|
| -save_string (const char *str, size_t len)
|
| -{
|
| - char *s;
|
| -
|
| - s = xmalloc (len + 1);
|
| - memcpy (s, str, len);
|
| - s[len] = '\0';
|
| -
|
| - return s;
|
| -}
|
| -
|
| /* Append another action to perform when the tracepoint triggers. */
|
|
|
| static void
|
| @@ -2034,7 +2037,7 @@ add_tracepoint_action (struct tracepoint *tpoint, char *packet)
|
| * tpoint->num_step_actions));
|
| tpoint->step_actions[tpoint->num_step_actions - 1] = action;
|
| tpoint->step_actions_str[tpoint->num_step_actions - 1]
|
| - = save_string (act_start, act - act_start);
|
| + = savestring (act_start, act - act_start);
|
| }
|
| else
|
| {
|
| @@ -2047,7 +2050,7 @@ add_tracepoint_action (struct tracepoint *tpoint, char *packet)
|
| sizeof (*tpoint->actions_str) * tpoint->numactions);
|
| tpoint->actions[tpoint->numactions - 1] = action;
|
| tpoint->actions_str[tpoint->numactions - 1]
|
| - = save_string (act_start, act - act_start);
|
| + = savestring (act_start, act - act_start);
|
| }
|
| }
|
| }
|
| @@ -2216,7 +2219,8 @@ add_traceframe (struct tracepoint *tpoint)
|
| /* Add a block to the traceframe currently being worked on. */
|
|
|
| static unsigned char *
|
| -add_traceframe_block (struct traceframe *tframe, int amt)
|
| +add_traceframe_block (struct traceframe *tframe,
|
| + struct tracepoint *tpoint, int amt)
|
| {
|
| unsigned char *block;
|
|
|
| @@ -2228,7 +2232,10 @@ add_traceframe_block (struct traceframe *tframe, int amt)
|
| if (!block)
|
| return NULL;
|
|
|
| + gdb_assert (tframe->tpnum == tpoint->number);
|
| +
|
| tframe->data_size += amt;
|
| + tpoint->traceframe_usage += amt;
|
|
|
| return block;
|
| }
|
| @@ -2358,6 +2365,8 @@ cmd_qtinit (char *packet)
|
| /* Make sure we don't try to read from a trace frame. */
|
| current_traceframe = -1;
|
|
|
| + stop_tracing ();
|
| +
|
| trace_debug ("Initializing the trace");
|
|
|
| clear_installed_tracepoints ();
|
| @@ -2808,7 +2817,7 @@ static void
|
| cmd_qtv (char *own_buf)
|
| {
|
| ULONGEST num;
|
| - LONGEST val;
|
| + LONGEST val = 0;
|
| int err;
|
| char *packet = own_buf;
|
|
|
| @@ -3657,14 +3666,15 @@ cmd_qtstatus (char *packet)
|
| "circular:%d;"
|
| "disconn:%d;"
|
| "starttime:%s;stoptime:%s;"
|
| - "username:%s:;notes:%s:",
|
| + "username:%s;notes:%s:",
|
| tracing ? 1 : 0,
|
| stop_reason_rsp, tracing_stop_tpnum,
|
| traceframe_count, traceframes_created,
|
| free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
|
| circular_trace_buffer,
|
| disconnected_tracing,
|
| - plongest (tracing_start_time), plongest (tracing_stop_time),
|
| + phex_nz (tracing_start_time, sizeof (tracing_start_time)),
|
| + phex_nz (tracing_stop_time, sizeof (tracing_stop_time)),
|
| buf1, buf2);
|
| }
|
|
|
| @@ -3698,8 +3708,8 @@ cmd_qtp (char *own_buf)
|
|
|
| /* State variables to help return all the tracepoint bits. */
|
| static struct tracepoint *cur_tpoint;
|
| -static int cur_action;
|
| -static int cur_step_action;
|
| +static unsigned int cur_action;
|
| +static unsigned int cur_step_action;
|
| static struct source_string *cur_source_string;
|
| static struct trace_state_variable *cur_tsv;
|
|
|
| @@ -3773,7 +3783,7 @@ cmd_qtfp (char *packet)
|
| trace_debug ("Returning first tracepoint definition piece");
|
|
|
| cur_tpoint = tracepoints;
|
| - cur_action = cur_step_action = -1;
|
| + cur_action = cur_step_action = 0;
|
| cur_source_string = NULL;
|
|
|
| if (cur_tpoint)
|
| @@ -3798,17 +3808,17 @@ cmd_qtsp (char *packet)
|
| GDB misbehavior. */
|
| strcpy (packet, "l");
|
| }
|
| - else if (cur_action < cur_tpoint->numactions - 1)
|
| + else if (cur_action < cur_tpoint->numactions)
|
| {
|
| - ++cur_action;
|
| response_action (packet, cur_tpoint,
|
| cur_tpoint->actions_str[cur_action], 0);
|
| + ++cur_action;
|
| }
|
| - else if (cur_step_action < cur_tpoint->num_step_actions - 1)
|
| + else if (cur_step_action < cur_tpoint->num_step_actions)
|
| {
|
| - ++cur_step_action;
|
| response_action (packet, cur_tpoint,
|
| cur_tpoint->step_actions_str[cur_step_action], 1);
|
| + ++cur_step_action;
|
| }
|
| else if ((cur_source_string
|
| ? cur_source_string->next
|
| @@ -3823,7 +3833,7 @@ cmd_qtsp (char *packet)
|
| else
|
| {
|
| cur_tpoint = cur_tpoint->next;
|
| - cur_action = cur_step_action = -1;
|
| + cur_action = cur_step_action = 0;
|
| cur_source_string = NULL;
|
| if (cur_tpoint)
|
| response_tracepoint (packet, cur_tpoint);
|
| @@ -3873,15 +3883,9 @@ cmd_qtfv (char *packet)
|
| static void
|
| cmd_qtsv (char *packet)
|
| {
|
| - trace_debug ("Returning first trace state variable definition");
|
| + trace_debug ("Returning additional trace state variable definition");
|
|
|
| - if (!cur_tpoint)
|
| - {
|
| - /* This case would normally never occur, but be prepared for
|
| - GDB misbehavior. */
|
| - strcpy (packet, "l");
|
| - }
|
| - else if (cur_tsv)
|
| + if (cur_tsv)
|
| {
|
| cur_tsv = cur_tsv->next;
|
| if (cur_tsv)
|
| @@ -3923,6 +3927,38 @@ cmd_qtstmat (char *packet)
|
| run_inferior_command (packet, strlen (packet) + 1);
|
| }
|
|
|
| +/* Sent the agent a command to close it. */
|
| +
|
| +void
|
| +gdb_agent_about_to_close (int pid)
|
| +{
|
| + char buf[IPA_CMD_BUF_SIZE];
|
| +
|
| + if (!maybe_write_ipa_not_loaded (buf))
|
| + {
|
| + struct thread_info *save_inferior;
|
| + struct inferior_list_entry *inf = all_threads.head;
|
| +
|
| + save_inferior = current_inferior;
|
| +
|
| + /* Find a certain thread which belongs to process PID. */
|
| + while (inf != NULL)
|
| + {
|
| + if (ptid_get_pid (inf->id) == pid)
|
| + break;
|
| + inf = inf->next;
|
| + }
|
| +
|
| + current_inferior = (struct thread_info *) inf;
|
| +
|
| + strcpy (buf, "close");
|
| +
|
| + run_inferior_command (buf, strlen (buf) + 1);
|
| +
|
| + current_inferior = save_inferior;
|
| + }
|
| +}
|
| +
|
| /* Return the minimum instruction size needed for fast tracepoints as a
|
| hexadecimal number. */
|
|
|
| @@ -3957,7 +3993,7 @@ cmd_qtbuffer (char *own_buf)
|
| unpack_varlen_hex (packet, &num);
|
|
|
| trace_debug ("Want to get trace buffer, %d bytes at offset 0x%s",
|
| - (int) num, pulongest (offset));
|
| + (int) num, phex_nz (offset, 0));
|
|
|
| tot = (trace_buffer_hi - trace_buffer_lo) - free_space ();
|
|
|
| @@ -3990,7 +4026,6 @@ cmd_qtbuffer (char *own_buf)
|
| num = (PBUFSIZ - 16) / 2;
|
|
|
| convert_int_to_ascii (tbp, own_buf, num);
|
| - own_buf[num] = '\0';
|
| }
|
|
|
| static void
|
| @@ -4009,6 +4044,37 @@ cmd_bigqtbuffer_circular (char *own_buf)
|
| }
|
|
|
| static void
|
| +cmd_bigqtbuffer_size (char *own_buf)
|
| +{
|
| + ULONGEST val;
|
| + LONGEST sval;
|
| + char *packet = own_buf;
|
| +
|
| + /* Can't change the size during a tracing run. */
|
| + if (tracing)
|
| + {
|
| + write_enn (own_buf);
|
| + return;
|
| + }
|
| +
|
| + packet += strlen ("QTBuffer:size:");
|
| +
|
| + /* -1 is sent as literal "-1". */
|
| + if (strcmp (packet, "-1") == 0)
|
| + sval = DEFAULT_TRACE_BUFFER_SIZE;
|
| + else
|
| + {
|
| + unpack_varlen_hex (packet, &val);
|
| + sval = (LONGEST) val;
|
| + }
|
| +
|
| + init_trace_buffer (sval);
|
| + trace_debug ("Trace buffer is now %s bytes",
|
| + plongest (trace_buffer_size));
|
| + write_ok (own_buf);
|
| +}
|
| +
|
| +static void
|
| cmd_qtnotes (char *own_buf)
|
| {
|
| size_t nbytes;
|
| @@ -4030,6 +4096,7 @@ cmd_qtnotes (char *own_buf)
|
| user[nbytes] = '\0';
|
| ++packet; /* skip the semicolon */
|
| trace_debug ("User is '%s'", user);
|
| + xfree (tracing_user_name);
|
| tracing_user_name = user;
|
| }
|
| else if (strncmp ("notes:", packet, strlen ("notes:")) == 0)
|
| @@ -4043,6 +4110,7 @@ cmd_qtnotes (char *own_buf)
|
| notes[nbytes] = '\0';
|
| ++packet; /* skip the semicolon */
|
| trace_debug ("Notes is '%s'", notes);
|
| + xfree (tracing_notes);
|
| tracing_notes = notes;
|
| }
|
| else if (strncmp ("tstop:", packet, strlen ("tstop:")) == 0)
|
| @@ -4056,6 +4124,7 @@ cmd_qtnotes (char *own_buf)
|
| stopnote[nbytes] = '\0';
|
| ++packet; /* skip the semicolon */
|
| trace_debug ("tstop note is '%s'", stopnote);
|
| + xfree (tracing_stop_note);
|
| tracing_stop_note = stopnote;
|
| }
|
| else
|
| @@ -4129,6 +4198,11 @@ handle_tracepoint_general_set (char *packet)
|
| cmd_bigqtbuffer_circular (packet);
|
| return 1;
|
| }
|
| + else if (strncmp ("QTBuffer:size:", packet, strlen ("QTBuffer:size:")) == 0)
|
| + {
|
| + cmd_bigqtbuffer_size (packet);
|
| + return 1;
|
| + }
|
| else if (strncmp ("QTNotes:", packet, strlen ("QTNotes:")) == 0)
|
| {
|
| cmd_qtnotes (packet);
|
| @@ -4613,6 +4687,14 @@ collect_data_at_step (struct tracepoint_hit_ctx *ctx,
|
|
|
| #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;
|
| +#endif
|
| +
|
| static struct regcache *
|
| get_context_regcache (struct tracepoint_hit_ctx *ctx)
|
| {
|
| @@ -4625,7 +4707,7 @@ get_context_regcache (struct tracepoint_hit_ctx *ctx)
|
| if (!fctx->regcache_initted)
|
| {
|
| fctx->regcache_initted = 1;
|
| - init_register_cache (&fctx->regcache, fctx->regspace);
|
| + init_register_cache (&fctx->regcache, ipa_tdesc, fctx->regspace);
|
| supply_regblock (&fctx->regcache, NULL);
|
| supply_fast_tracepoint_registers (&fctx->regcache, fctx->regs);
|
| }
|
| @@ -4640,7 +4722,7 @@ get_context_regcache (struct tracepoint_hit_ctx *ctx)
|
| if (!sctx->regcache_initted)
|
| {
|
| sctx->regcache_initted = 1;
|
| - init_register_cache (&sctx->regcache, sctx->regspace);
|
| + init_register_cache (&sctx->regcache, ipa_tdesc, sctx->regspace);
|
| supply_regblock (&sctx->regcache, NULL);
|
| /* Pass down the tracepoint address, because REGS doesn't
|
| include the PC, but we know what it must have been. */
|
| @@ -4679,15 +4761,19 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
| case 'M':
|
| {
|
| struct collect_memory_action *maction;
|
| + struct eval_agent_expr_context ax_ctx;
|
|
|
| maction = (struct collect_memory_action *) taction;
|
| + ax_ctx.regcache = NULL;
|
| + ax_ctx.tframe = tframe;
|
| + ax_ctx.tpoint = tpoint;
|
|
|
| trace_debug ("Want to collect %s bytes at 0x%s (basereg %d)",
|
| pulongest (maction->len),
|
| paddress (maction->addr), maction->basereg);
|
| /* (should use basereg) */
|
| - agent_mem_read (tframe, NULL,
|
| - (CORE_ADDR) maction->addr, maction->len);
|
| + agent_mem_read (&ax_ctx, NULL, (CORE_ADDR) maction->addr,
|
| + maction->len);
|
| break;
|
| }
|
| case 'R':
|
| @@ -4695,13 +4781,15 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
| unsigned char *regspace;
|
| struct regcache tregcache;
|
| struct regcache *context_regcache;
|
| -
|
| + int regcache_size;
|
|
|
| trace_debug ("Want to collect registers");
|
|
|
| + context_regcache = get_context_regcache (ctx);
|
| + regcache_size = register_cache_size (context_regcache->tdesc);
|
| +
|
| /* Collect all registers for now. */
|
| - regspace = add_traceframe_block (tframe,
|
| - 1 + register_cache_size ());
|
| + regspace = add_traceframe_block (tframe, tpoint, 1 + regcache_size);
|
| if (regspace == NULL)
|
| {
|
| trace_debug ("Trace buffer block allocation failed, skipping");
|
| @@ -4710,11 +4798,10 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
| /* Identify a register block. */
|
| *regspace = 'R';
|
|
|
| - context_regcache = get_context_regcache (ctx);
|
| -
|
| /* Wrap the regblock in a register cache (in the stack, we
|
| don't want to malloc here). */
|
| - init_register_cache (&tregcache, regspace + 1);
|
| + init_register_cache (&tregcache, context_regcache->tdesc,
|
| + regspace + 1);
|
|
|
| /* Copy the register data to the regblock. */
|
| regcache_cpy (&tregcache, context_regcache);
|
| @@ -4742,12 +4829,16 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
| case 'X':
|
| {
|
| struct eval_expr_action *eaction;
|
| + struct eval_agent_expr_context ax_ctx;
|
|
|
| eaction = (struct eval_expr_action *) taction;
|
| + ax_ctx.regcache = get_context_regcache (ctx);
|
| + ax_ctx.tframe = tframe;
|
| + ax_ctx.tpoint = tpoint;
|
|
|
| trace_debug ("Want to evaluate expression");
|
|
|
| - err = eval_tracepoint_agent_expr (ctx, tframe, eaction->expr, NULL);
|
| + err = gdb_eval_agent_expr (&ax_ctx, eaction->expr, NULL);
|
|
|
| if (err != expr_eval_no_error)
|
| {
|
| @@ -4799,8 +4890,15 @@ condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
| err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (ctx, &value);
|
| else
|
| #endif
|
| - err = eval_tracepoint_agent_expr (ctx, NULL, tpoint->cond, &value);
|
| + {
|
| + struct eval_agent_expr_context ax_ctx;
|
|
|
| + ax_ctx.regcache = get_context_regcache (ctx);
|
| + ax_ctx.tframe = NULL;
|
| + ax_ctx.tpoint = tpoint;
|
| +
|
| + err = gdb_eval_agent_expr (&ax_ctx, tpoint->cond, &value);
|
| + }
|
| if (err != expr_eval_no_error)
|
| {
|
| record_tracepoint_error (tpoint, "condition", err);
|
| @@ -4814,27 +4912,11 @@ condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
| return (value ? 1 : 0);
|
| }
|
|
|
| -/* Evaluates a tracepoint agent expression with context CTX,
|
| - traceframe TFRAME, agent expression AEXPR and store the
|
| - result in RSLT. */
|
| -
|
| -static enum eval_result_type
|
| -eval_tracepoint_agent_expr (struct tracepoint_hit_ctx *ctx,
|
| - struct traceframe *tframe,
|
| - struct agent_expr *aexpr,
|
| - ULONGEST *rslt)
|
| -{
|
| - struct regcache *regcache;
|
| - regcache = get_context_regcache (ctx);
|
| -
|
| - return gdb_eval_agent_expr (regcache, tframe, aexpr, rslt);
|
| -}
|
| -
|
| /* Do memory copies for bytecodes. */
|
| /* Do the recording of memory blocks for actions and bytecodes. */
|
|
|
| int
|
| -agent_mem_read (struct traceframe *tframe,
|
| +agent_mem_read (struct eval_agent_expr_context *ctx,
|
| unsigned char *to, CORE_ADDR from, ULONGEST len)
|
| {
|
| unsigned char *mspace;
|
| @@ -4855,7 +4937,7 @@ agent_mem_read (struct traceframe *tframe,
|
|
|
| blocklen = (remaining > 65535 ? 65535 : remaining);
|
| sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen;
|
| - mspace = add_traceframe_block (tframe, sp);
|
| + mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp);
|
| if (mspace == NULL)
|
| return 1;
|
| /* Identify block as a memory block. */
|
| @@ -4876,7 +4958,7 @@ agent_mem_read (struct traceframe *tframe,
|
| }
|
|
|
| int
|
| -agent_mem_read_string (struct traceframe *tframe,
|
| +agent_mem_read_string (struct eval_agent_expr_context *ctx,
|
| unsigned char *to, CORE_ADDR from, ULONGEST len)
|
| {
|
| unsigned char *buf, *mspace;
|
| @@ -4912,7 +4994,7 @@ agent_mem_read_string (struct traceframe *tframe,
|
| }
|
| }
|
| sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen;
|
| - mspace = add_traceframe_block (tframe, sp);
|
| + mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp);
|
| if (mspace == NULL)
|
| {
|
| xfree (buf);
|
| @@ -4938,12 +5020,12 @@ agent_mem_read_string (struct traceframe *tframe,
|
| /* Record the value of a trace state variable. */
|
|
|
| int
|
| -agent_tsv_read (struct traceframe *tframe, int n)
|
| +agent_tsv_read (struct eval_agent_expr_context *ctx, int n)
|
| {
|
| unsigned char *vspace;
|
| LONGEST val;
|
|
|
| - vspace = add_traceframe_block (tframe,
|
| + vspace = add_traceframe_block (ctx->tframe, ctx->tpoint,
|
| 1 + sizeof (n) + sizeof (LONGEST));
|
| if (vspace == NULL)
|
| return 1;
|
| @@ -5022,7 +5104,7 @@ traceframe_walk_blocks (unsigned char *database, unsigned int datasize,
|
| {
|
| case 'R':
|
| /* Skip over the registers block. */
|
| - dataptr += register_cache_size ();
|
| + dataptr += current_target_desc ()->registers_size;
|
| break;
|
| case 'M':
|
| /* Skip over the memory block. */
|
| @@ -5117,12 +5199,13 @@ traceframe_get_pc (struct traceframe *tframe)
|
| {
|
| struct regcache regcache;
|
| unsigned char *dataptr;
|
| + const struct target_desc *tdesc = current_target_desc ();
|
|
|
| dataptr = traceframe_find_regblock (tframe, -1);
|
| if (dataptr == NULL)
|
| return 0;
|
|
|
| - init_register_cache (®cache, dataptr);
|
| + init_register_cache (®cache, tdesc, dataptr);
|
| return regcache_read_pc (®cache);
|
| }
|
|
|
| @@ -5198,6 +5281,7 @@ traceframe_read_tsv (int tsvnum, LONGEST *val)
|
| unsigned char *database, *dataptr;
|
| unsigned int datasize;
|
| int vnum;
|
| + int found = 0;
|
|
|
| trace_debug ("traceframe_read_tsv");
|
|
|
| @@ -5220,7 +5304,8 @@ traceframe_read_tsv (int tsvnum, LONGEST *val)
|
| datasize = tframe->data_size;
|
| database = dataptr = &tframe->data[0];
|
|
|
| - /* Iterate through a traceframe's blocks, looking for the tsv. */
|
| + /* Iterate through a traceframe's blocks, looking for the last
|
| + matched tsv. */
|
| while ((dataptr = traceframe_find_block_type (dataptr,
|
| datasize
|
| - (dataptr - database),
|
| @@ -5235,16 +5320,17 @@ traceframe_read_tsv (int tsvnum, LONGEST *val)
|
| if (tsvnum == vnum)
|
| {
|
| memcpy (val, dataptr, sizeof (*val));
|
| - return 0;
|
| + found = 1;
|
| }
|
|
|
| /* Skip over this block. */
|
| dataptr += sizeof (LONGEST);
|
| }
|
|
|
| - trace_debug ("traceframe %d has no data for variable %d",
|
| - tfnum, tsvnum);
|
| - return 1;
|
| + if (!found)
|
| + trace_debug ("traceframe %d has no data for variable %d",
|
| + tfnum, tsvnum);
|
| + return !found;
|
| }
|
|
|
| /* Read a requested block of static tracepoint data from a trace
|
| @@ -5326,6 +5412,13 @@ build_traceframe_info_xml (char blocktype, unsigned char *dataptr, void *data)
|
| break;
|
| }
|
| case 'V':
|
| + {
|
| + int vnum;
|
| +
|
| + memcpy (&vnum, dataptr, sizeof (vnum));
|
| + buffer_xml_printf (buffer, "<tvar id=\"%d\"/>\n", vnum);
|
| + break;
|
| + }
|
| case 'R':
|
| case 'S':
|
| {
|
| @@ -5673,7 +5766,7 @@ gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
|
| ctx.regcache_initted = 0;
|
| /* Wrap the regblock in a register cache (in the stack, we don't
|
| want to malloc here). */
|
| - ctx.regspace = alloca (register_cache_size ());
|
| + ctx.regspace = alloca (ipa_tdesc->registers_size);
|
| if (ctx.regspace == NULL)
|
| {
|
| trace_debug ("Trace buffer block allocation failed, skipping");
|
| @@ -5930,7 +6023,7 @@ download_tracepoint_1 (struct tracepoint *tpoint)
|
|
|
| if (ipa_action != 0)
|
| write_inferior_data_ptr
|
| - (actions_array + i * sizeof (sizeof (*tpoint->actions)),
|
| + (actions_array + i * sizeof (*tpoint->actions),
|
| ipa_action);
|
| }
|
| }
|
| @@ -6320,7 +6413,8 @@ upload_fast_traceframes (void)
|
| {
|
| /* Copy the whole set of blocks in one go for now. FIXME:
|
| split this in smaller blocks. */
|
| - block = add_traceframe_block (tframe, ipa_tframe.data_size);
|
| + block = add_traceframe_block (tframe, tpoint,
|
| + ipa_tframe.data_size);
|
| if (block != NULL)
|
| {
|
| if (read_inferior_memory (tf
|
| @@ -6532,7 +6626,7 @@ gdb_probe (const struct marker *mdata, void *probe_private,
|
|
|
| /* Wrap the regblock in a register cache (in the stack, we don't
|
| want to malloc here). */
|
| - ctx.regspace = alloca (register_cache_size ());
|
| + ctx.regspace = alloca (ipa_tdesc->registers_size);
|
| if (ctx.regspace == NULL)
|
| {
|
| trace_debug ("Trace buffer block allocation failed, skipping");
|
| @@ -6619,7 +6713,7 @@ collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
| trace_debug ("Want to collect ust data");
|
|
|
| /* 'S' + size + string */
|
| - bufspace = add_traceframe_block (tframe,
|
| + bufspace = add_traceframe_block (tframe, umd->tpoint,
|
| 1 + sizeof (blocklen) + size + 1);
|
| if (bufspace == NULL)
|
| {
|
| @@ -6666,7 +6760,7 @@ static int
|
| run_inferior_command (char *cmd, int len)
|
| {
|
| int err = -1;
|
| - int pid = ptid_get_pid (current_inferior->entry.id);
|
| + int pid = ptid_get_pid (current_ptid);
|
|
|
| trace_debug ("run_inferior_command: running: %s", cmd);
|
|
|
| @@ -6748,13 +6842,14 @@ init_named_socket (const char *name)
|
| return fd;
|
| }
|
|
|
| +static char agent_socket_name[UNIX_PATH_MAX];
|
| +
|
| static int
|
| gdb_agent_socket_init (void)
|
| {
|
| int result, fd;
|
| - char name[UNIX_PATH_MAX];
|
|
|
| - result = xsnprintf (name, UNIX_PATH_MAX, "%s/gdb_ust%d",
|
| + result = xsnprintf (agent_socket_name, UNIX_PATH_MAX, "%s/gdb_ust%d",
|
| SOCK_DIR, getpid ());
|
| if (result >= UNIX_PATH_MAX)
|
| {
|
| @@ -6762,11 +6857,11 @@ gdb_agent_socket_init (void)
|
| return -1;
|
| }
|
|
|
| - fd = init_named_socket (name);
|
| + fd = init_named_socket (agent_socket_name);
|
| if (fd < 0)
|
| warning ("Error initializing named socket (%s) for communication with the "
|
| "ust helper thread. Check that directory exists and that it "
|
| - "is writable.", name);
|
| + "is writable.", agent_socket_name);
|
|
|
| return fd;
|
| }
|
| @@ -6995,6 +7090,13 @@ gdb_ust_init (void)
|
| #endif /* HAVE_UST */
|
|
|
| #include <sys/syscall.h>
|
| +#include <stdlib.h>
|
| +
|
| +static void
|
| +gdb_agent_remove_socket (void)
|
| +{
|
| + unlink (agent_socket_name);
|
| +}
|
|
|
| /* Helper thread of agent. */
|
|
|
| @@ -7003,6 +7105,8 @@ gdb_agent_helper_thread (void *arg)
|
| {
|
| int listen_fd;
|
|
|
| + atexit (gdb_agent_remove_socket);
|
| +
|
| while (1)
|
| {
|
| listen_fd = gdb_agent_socket_init ();
|
| @@ -7023,6 +7127,7 @@ gdb_agent_helper_thread (void *arg)
|
| int fd;
|
| char buf[1];
|
| int ret;
|
| + int stop_loop = 0;
|
|
|
| tmp = sizeof (sockaddr);
|
|
|
| @@ -7055,8 +7160,12 @@ gdb_agent_helper_thread (void *arg)
|
|
|
| if (cmd_buf[0])
|
| {
|
| + if (strncmp ("close", cmd_buf, 5) == 0)
|
| + {
|
| + stop_loop = 1;
|
| + }
|
| #ifdef HAVE_UST
|
| - if (strcmp ("qTfSTM", cmd_buf) == 0)
|
| + else if (strcmp ("qTfSTM", cmd_buf) == 0)
|
| {
|
| cmd_qtfstm (cmd_buf);
|
| }
|
| @@ -7088,6 +7197,20 @@ gdb_agent_helper_thread (void *arg)
|
| /* Fix compiler's warning: ignoring return value of 'write'. */
|
| ret = write (fd, buf, 1);
|
| close (fd);
|
| +
|
| + if (stop_loop)
|
| + {
|
| + close (listen_fd);
|
| + unlink (agent_socket_name);
|
| +
|
| + /* Sleep endlessly to wait the whole inferior stops. This
|
| + thread can not exit because GDB or GDBserver may still need
|
| + 'current_inferior' (representing this thread) to access
|
| + inferior memory. Otherwise, this thread exits earlier than
|
| + other threads, and 'current_inferior' is set to NULL. */
|
| + while (1)
|
| + sleep (10);
|
| + }
|
| }
|
| }
|
|
|
| @@ -7185,10 +7308,8 @@ get_timestamp (void)
|
| void
|
| initialize_tracepoint (void)
|
| {
|
| - /* There currently no way to change the buffer size. */
|
| - const int sizeOfBuffer = 5 * 1024 * 1024;
|
| - unsigned char *buf = xmalloc (sizeOfBuffer);
|
| - init_trace_buffer (buf, sizeOfBuffer);
|
| + /* Start with the default size. */
|
| + init_trace_buffer (DEFAULT_TRACE_BUFFER_SIZE);
|
|
|
| /* Wire trace state variable 1 to be the timestamp. This will be
|
| uploaded to GDB upon connection and become one of its trace state
|
|
|