X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Ftracepoint.c;h=8e294f64c0b8a7a6307070e431612806f40e984c;hb=ff0e980e6f720fe49608a5a0a37be3a28258c9d7;hp=03cb7cd0d7d7ed372916c9ff2a41a8d2f5fbd499;hpb=5f18041e78f879768645b113054261313517234a;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 03cb7cd0d7..8e294f64c0 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-2014 Free Software Foundation, Inc. This file is part of GDB. @@ -17,7 +17,10 @@ along with this program. If not, see . */ #include "server.h" +#include "tracepoint.h" +#include "gdbthread.h" #include "agent.h" +#include "rsp-low.h" #include #include @@ -28,6 +31,9 @@ #include #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 @@ -56,7 +62,9 @@ */ -static void trace_vdebug (const char *, ...) ATTR_FORMAT (printf, 1, 2); +#ifdef IN_PROCESS_AGENT + +static void trace_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2); static void trace_vdebug (const char *fmt, ...) @@ -76,6 +84,19 @@ trace_vdebug (const char *fmt, ...) trace_vdebug ((fmt), ##args); \ } while (0) +#else + +#define trace_debug_1(level, fmt, args...) \ + do { \ + if (level <= debug_threads) \ + { \ + debug_printf ((fmt), ##args); \ + debug_printf ("\n"); \ + } \ + } while (0) + +#endif + #define trace_debug(FMT, args...) \ trace_debug_1 (1, FMT, ##args) @@ -333,7 +354,7 @@ tracepoint_look_up_symbols (void) if (look_up_one_symbol (symbol_list[i].name, addrp, 1) == 0) { if (debug_threads) - fprintf (stderr, "symbol `%s' not found\n", symbol_list[i].name); + debug_printf ("symbol `%s' not found\n", symbol_list[i].name); return; } } @@ -408,11 +429,10 @@ static int stop_tracing_handler (CORE_ADDR); struct breakpoint *flush_trace_buffer_bkpt; static int flush_trace_buffer_handler (CORE_ADDR); -static void download_tracepoints (void); static void download_trace_state_variables (void); static void upload_fast_traceframes (void); -static int run_inferior_command (char *cmd); +static int run_inferior_command (char *cmd, int len); static int read_inferior_integer (CORE_ADDR symaddr, int *val) @@ -421,6 +441,9 @@ read_inferior_integer (CORE_ADDR symaddr, int *val) sizeof (*val)); } +struct tracepoint; +static int tracepoint_send_agent (struct tracepoint *tpoint); + static int read_inferior_uinteger (CORE_ADDR symaddr, unsigned int *val) { @@ -461,6 +484,13 @@ write_inferior_uinteger (CORE_ADDR symaddr, unsigned int 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 { \ + memcpy (BUF, &(OBJ)->FIELD, sizeof ((OBJ)->FIELD)); \ + BUF += sizeof ((OBJ)->FIELD); \ + } while (0) + #endif /* Operations on various types of tracepoint actions. */ @@ -472,6 +502,10 @@ 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. */ @@ -529,10 +563,23 @@ m_tracepoint_action_download (const struct tracepoint_action *action) return ipa_action; } +static char * +m_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) +{ + struct collect_memory_action *maction + = (struct collect_memory_action *) action; + + COPY_FIELD_TO_BUF (buffer, maction, addr); + COPY_FIELD_TO_BUF (buffer, maction, len); + COPY_FIELD_TO_BUF (buffer, maction, basereg); + + return buffer; +} static const struct tracepoint_action_ops m_tracepoint_action_ops = { m_tracepoint_action_download, + m_tracepoint_action_send, }; static CORE_ADDR @@ -548,9 +595,16 @@ r_tracepoint_action_download (const struct tracepoint_action *action) return ipa_action; } +static char * +r_tracepoint_action_send (char *buffer, const struct tracepoint_action *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); @@ -573,9 +627,42 @@ x_tracepoint_action_download (const struct tracepoint_action *action) return ipa_action; } +/* Copy agent expression AEXPR to buffer pointed by P. If AEXPR is NULL, + copy 0 to P. Return updated header of buffer. */ + +static char * +agent_expr_send (char *p, const struct agent_expr *aexpr) +{ + /* Copy the length of condition first, and then copy its + content. */ + if (aexpr == NULL) + { + memset (p, 0, 4); + p += 4; + } + else + { + memcpy (p, &aexpr->length, 4); + p +=4; + + memcpy (p, aexpr->bytes, aexpr->length); + p += aexpr->length; + } + return p; +} + +static char * +x_tracepoint_action_send ( char *buffer, const struct tracepoint_action *action) +{ + struct eval_expr_action *eaction = (struct eval_expr_action *) 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 @@ -591,9 +678,16 @@ l_tracepoint_action_download (const struct tracepoint_action *action) return ipa_action; } +static char * +l_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) +{ + return buffer; +} + static const struct tracepoint_action_ops l_tracepoint_action_ops = { l_tracepoint_action_download, + l_tracepoint_action_send, }; #endif @@ -905,6 +999,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. */ @@ -918,6 +1016,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; @@ -1272,12 +1374,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); @@ -1410,10 +1506,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 (); } @@ -1453,7 +1558,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: @@ -1828,18 +1933,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 @@ -1960,7 +2053,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 { @@ -1973,7 +2066,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); } } } @@ -2142,7 +2235,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; @@ -2154,7 +2248,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; } @@ -2284,6 +2381,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 (); @@ -2331,7 +2430,7 @@ unprobe_marker_at (CORE_ADDR address) char cmd[IPA_CMD_BUF_SIZE]; sprintf (cmd, "unprobe_marker_at:%s", paddress (address)); - run_inferior_command (cmd); + run_inferior_command (cmd, strlen (cmd) + 1); } /* Restore the program to its pre-tracing state. This routine may be called @@ -2537,16 +2636,31 @@ cmd_qtdp (char *own_buf) } } - download_tracepoint (tpoint); - - if (tpoint->type == trap_tracepoint || tp == NULL) + if (use_agent && tpoint->type == fast_tracepoint + && agent_capability_check (AGENT_CAPA_FAST_TRACE)) { - install_tracepoint (tpoint, own_buf); - if (strcmp (own_buf, "OK") != 0) - remove_tracepoint (tpoint); + /* Download and install fast tracepoint by agent. */ + if (tracepoint_send_agent (tpoint) == 0) + write_ok (own_buf); + else + { + write_enn (own_buf); + remove_tracepoint (tpoint); + } } else - write_ok (own_buf); + { + download_tracepoint (tpoint); + + if (tpoint->type == trap_tracepoint || tp == NULL) + { + install_tracepoint (tpoint, own_buf); + if (strcmp (own_buf, "OK") != 0) + remove_tracepoint (tpoint); + } + else + write_ok (own_buf); + } unpause_all (1); return; @@ -2594,7 +2708,7 @@ cmd_qtdpsrc (char *own_buf) packet = unpack_varlen_hex (packet, &slen); ++packet; /* skip a colon */ src = xmalloc (slen + 1); - nbytes = unhexify (src, packet, strlen (packet) / 2); + nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2); src[nbytes] = '\0'; newlast = xmalloc (sizeof (struct source_string)); @@ -2636,7 +2750,7 @@ cmd_qtdv (char *own_buf) nbytes = strlen (packet) / 2; varname = xmalloc (nbytes + 1); - nbytes = unhexify (varname, packet, nbytes); + nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes); varname[nbytes] = '\0'; tsv = create_trace_state_variable (num, 1); @@ -2719,7 +2833,7 @@ static void cmd_qtv (char *own_buf) { ULONGEST num; - LONGEST val; + LONGEST val = 0; int err; char *packet = own_buf; @@ -2937,7 +3051,7 @@ probe_marker_at (CORE_ADDR address, char *errout) int err; sprintf (cmd, "probe_marker_at:%s", paddress (address)); - err = run_inferior_command (cmd); + err = run_inferior_command (cmd, strlen (cmd) + 1); if (err == 0) { @@ -3088,10 +3202,13 @@ install_tracepoint (struct tracepoint *tpoint, char *own_buf) write_ok (own_buf); } +static void download_tracepoint_1 (struct tracepoint *tpoint); + static void cmd_qtstart (char *packet) { struct tracepoint *tpoint, *prev_ftpoint, *prev_stpoint; + CORE_ADDR tpptr = 0, prev_tpptr = 0; trace_debug ("Starting the trace"); @@ -3109,10 +3226,7 @@ cmd_qtstart (char *packet) /* Sync the fast tracepoints list in the inferior ftlib. */ if (agent_loaded_p ()) - { - download_tracepoints (); - download_trace_state_variables (); - } + download_trace_state_variables (); /* No previous fast tpoint yet. */ prev_ftpoint = NULL; @@ -3122,7 +3236,11 @@ cmd_qtstart (char *packet) *packet = '\0'; - /* Install tracepoints. */ + /* Start out empty. */ + if (agent_loaded_p ()) + write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, 0); + + /* Download and install tracepoints. */ for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) { /* Ensure all the hit counts start at zero. */ @@ -3138,48 +3256,89 @@ cmd_qtstart (char *packet) tpoint->handle = set_breakpoint_at (tpoint->address, tracepoint_handler); } - else if (tpoint->type == fast_tracepoint) + else if (tpoint->type == fast_tracepoint + || tpoint->type == static_tracepoint) { if (maybe_write_ipa_not_loaded (packet)) { - trace_debug ("Requested a fast tracepoint, but fast " - "tracepoints aren't supported."); + trace_debug ("Requested a %s tracepoint, but fast " + "tracepoints aren't supported.", + tpoint->type == static_tracepoint + ? "static" : "fast"); break; } - if (prev_ftpoint != NULL && prev_ftpoint->address == tpoint->address) - clone_fast_tracepoint (tpoint, prev_ftpoint); - else + if (tpoint->type == fast_tracepoint) { - if (install_fast_tracepoint (tpoint, packet) == 0) - prev_ftpoint = tpoint; - } - } - else if (tpoint->type == static_tracepoint) - { - if (maybe_write_ipa_ust_not_loaded (packet)) - { - trace_debug ("Requested a static tracepoint, but static " - "tracepoints are not supported."); - break; - } + int use_agent_p + = use_agent && agent_capability_check (AGENT_CAPA_FAST_TRACE); - /* Can only probe a given marker once. */ - if (prev_stpoint != NULL && prev_stpoint->address == tpoint->address) - { - tpoint->handle = (void *) -1; + if (prev_ftpoint != NULL + && prev_ftpoint->address == tpoint->address) + { + if (use_agent_p) + tracepoint_send_agent (tpoint); + else + download_tracepoint_1 (tpoint); + + clone_fast_tracepoint (tpoint, prev_ftpoint); + } + else + { + /* Tracepoint is installed successfully? */ + int installed = 0; + + /* Download and install fast tracepoint by agent. */ + if (use_agent_p) + installed = !tracepoint_send_agent (tpoint); + else + { + download_tracepoint_1 (tpoint); + installed = !install_fast_tracepoint (tpoint, packet); + } + + if (installed) + prev_ftpoint = tpoint; + } } else { - if (probe_marker_at (tpoint->address, packet) == 0) + if (!in_process_agent_supports_ust ()) { - tpoint->handle = (void *) -1; + trace_debug ("Requested a static tracepoint, but static " + "tracepoints are not supported."); + break; + } - /* So that we can handle multiple static tracepoints - at the same address easily. */ - prev_stpoint = tpoint; + download_tracepoint_1 (tpoint); + /* Can only probe a given marker once. */ + if (prev_stpoint != NULL + && prev_stpoint->address == tpoint->address) + tpoint->handle = (void *) -1; + else + { + if (probe_marker_at (tpoint->address, packet) == 0) + { + tpoint->handle = (void *) -1; + + /* So that we can handle multiple static tracepoints + at the same address easily. */ + prev_stpoint = tpoint; + } } } + + prev_tpptr = tpptr; + tpptr = tpoint->obj_addr_on_target; + + if (tpoint == tracepoints) + /* First object in list, set the head pointer in the + inferior. */ + write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, tpptr); + else + write_inferior_data_ptr (prev_tpptr + offsetof (struct tracepoint, + next), + tpptr); } /* Any failure in the inner loop is sufficient cause to give @@ -3464,17 +3623,17 @@ cmd_qtstatus (char *packet) str = (tracing_user_name ? tracing_user_name : ""); slen = strlen (str); buf1 = (char *) alloca (slen * 2 + 1); - hexify (buf1, str, slen); + bin2hex ((gdb_byte *) str, buf1, slen); str = (tracing_notes ? tracing_notes : ""); slen = strlen (str); buf2 = (char *) alloca (slen * 2 + 1); - hexify (buf2, str, slen); + bin2hex ((gdb_byte *) str, buf2, slen); str = (tracing_stop_note ? tracing_stop_note : ""); slen = strlen (str); buf3 = (char *) alloca (slen * 2 + 1); - hexify (buf3, str, slen); + bin2hex ((gdb_byte *) str, buf3, slen); trace_debug ("Returning trace status as %d, stop reason %s", tracing, tracing_stop_reason); @@ -3504,7 +3663,7 @@ cmd_qtstatus (char *packet) p = stop_reason_rsp = alloca (strlen ("terror:") + hexstr_len + 1); strcpy (p, "terror:"); p += strlen (p); - convert_int_to_ascii ((gdb_byte *) result_name, p, strlen (result_name)); + bin2hex ((gdb_byte *) result_name, p, strlen (result_name)); } /* If this was a forced stop, include any stop note that was supplied. */ @@ -3523,14 +3682,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); } @@ -3564,8 +3724,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; @@ -3622,7 +3782,7 @@ response_source (char *packet, len = strlen (src->str); buf = alloca (len * 2 + 1); - convert_int_to_ascii ((gdb_byte *) src->str, buf, len); + bin2hex ((gdb_byte *) src->str, buf, len); sprintf (packet, "Z%x:%s:%s:%x:%x:%s", tpoint->number, paddress (tpoint->address), @@ -3639,7 +3799,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) @@ -3664,17 +3824,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 @@ -3689,7 +3849,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); @@ -3711,7 +3871,7 @@ response_tsv (char *packet, struct trace_state_variable *tsv) { namelen = strlen (tsv->name); buf = alloca (namelen * 2 + 1); - convert_int_to_ascii ((gdb_byte *) tsv->name, buf, namelen); + bin2hex ((gdb_byte *) tsv->name, buf, namelen); } sprintf (packet, "%x:%s:%x:%s", tsv->number, phex_nz (tsv->initial_value, 0), @@ -3739,15 +3899,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) @@ -3767,7 +3921,7 @@ static void cmd_qtfstm (char *packet) { if (!maybe_write_ipa_ust_not_loaded (packet)) - run_inferior_command (packet); + run_inferior_command (packet, strlen (packet) + 1); } /* Return additional static tracepoints markers. */ @@ -3776,7 +3930,7 @@ static void cmd_qtsstm (char *packet) { if (!maybe_write_ipa_ust_not_loaded (packet)) - run_inferior_command (packet); + run_inferior_command (packet, strlen (packet) + 1); } /* Return the definition of the static tracepoint at a given address. @@ -3786,7 +3940,39 @@ static void cmd_qtstmat (char *packet) { if (!maybe_write_ipa_ust_not_loaded (packet)) - run_inferior_command (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 @@ -3823,7 +4009,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 (); @@ -3855,8 +4041,7 @@ cmd_qtbuffer (char *own_buf) if (num >= (PBUFSIZ - 16) / 2 ) num = (PBUFSIZ - 16) / 2; - convert_int_to_ascii (tbp, own_buf, num); - own_buf[num] = '\0'; + bin2hex (tbp, own_buf, num); } static void @@ -3874,6 +4059,37 @@ cmd_bigqtbuffer_circular (char *own_buf) write_ok (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) { @@ -3892,10 +4108,11 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; user = xmalloc (nbytes + 1); - nbytes = unhexify (user, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) user, nbytes); 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) @@ -3905,10 +4122,11 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; notes = xmalloc (nbytes + 1); - nbytes = unhexify (notes, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes); 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) @@ -3918,10 +4136,11 @@ cmd_qtnotes (char *own_buf) packet = strchr (packet, ';'); nbytes = (packet - saved) / 2; stopnote = xmalloc (nbytes + 1); - nbytes = unhexify (stopnote, saved, nbytes); + nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes); stopnote[nbytes] = '\0'; ++packet; /* skip the semicolon */ trace_debug ("tstop note is '%s'", stopnote); + xfree (tracing_stop_note); tracing_stop_note = stopnote; } else @@ -3995,6 +4214,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); @@ -4479,6 +4703,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) { @@ -4491,7 +4723,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); } @@ -4506,7 +4738,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. */ @@ -4545,15 +4777,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': @@ -4561,13 +4797,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"); @@ -4576,11 +4814,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); @@ -4608,12 +4845,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) { @@ -4665,8 +4906,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); @@ -4680,27 +4928,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; @@ -4721,7 +4953,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. */ @@ -4742,7 +4974,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; @@ -4778,7 +5010,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); @@ -4804,12 +5036,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; @@ -4888,7 +5120,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. */ @@ -4983,12 +5215,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); } @@ -5064,6 +5297,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"); @@ -5086,7 +5320,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), @@ -5101,16 +5336,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 @@ -5192,6 +5428,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, "\n", vnum); + break; + } case 'R': case 'S': { @@ -5539,7 +5782,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"); @@ -5796,12 +6039,97 @@ 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); } } } +#define IPA_PROTO_FAST_TRACE_FLAG 0 +#define IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET 2 +#define IPA_PROTO_FAST_TRACE_JUMP_PAD 10 +#define IPA_PROTO_FAST_TRACE_FJUMP_SIZE 18 +#define IPA_PROTO_FAST_TRACE_FJUMP_INSN 22 + +/* Send a command to agent to download and install tracepoint TPOINT. */ + +static int +tracepoint_send_agent (struct tracepoint *tpoint) +{ + char buf[IPA_CMD_BUF_SIZE]; + char *p; + int i, ret; + + p = buf; + strcpy (p, "FastTrace:"); + p += 10; + + COPY_FIELD_TO_BUF (p, tpoint, number); + COPY_FIELD_TO_BUF (p, tpoint, address); + COPY_FIELD_TO_BUF (p, tpoint, type); + COPY_FIELD_TO_BUF (p, tpoint, enabled); + COPY_FIELD_TO_BUF (p, tpoint, step_count); + COPY_FIELD_TO_BUF (p, tpoint, pass_count); + COPY_FIELD_TO_BUF (p, tpoint, numactions); + COPY_FIELD_TO_BUF (p, tpoint, hit_count); + COPY_FIELD_TO_BUF (p, tpoint, traceframe_usage); + COPY_FIELD_TO_BUF (p, tpoint, compiled_cond); + COPY_FIELD_TO_BUF (p, tpoint, orig_size); + + /* condition */ + p = agent_expr_send (p, tpoint->cond); + + /* tracepoint_action */ + for (i = 0; i < tpoint->numactions; i++) + { + struct tracepoint_action *action = tpoint->actions[i]; + + p[0] = action->type; + p = action->ops->send (&p[1], action); + } + + get_jump_space_head (); + /* Copy the value of GDB_JUMP_PAD_HEAD to command buffer, so that + agent can use jump pad from it. */ + if (tpoint->type == fast_tracepoint) + { + memcpy (p, &gdb_jump_pad_head, 8); + p += 8; + } + + ret = run_inferior_command (buf, (int) (ptrdiff_t) (p - buf)); + if (ret) + return ret; + + if (strncmp (buf, "OK", 2) != 0) + return 1; + + /* The value of tracepoint's target address is stored in BUF. */ + memcpy (&tpoint->obj_addr_on_target, + &buf[IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET], 8); + + if (tpoint->type == fast_tracepoint) + { + unsigned char *insn + = (unsigned char *) &buf[IPA_PROTO_FAST_TRACE_FJUMP_INSN]; + int fjump_size; + + trace_debug ("agent: read from cmd_buf 0x%x 0x%x\n", + (unsigned int) tpoint->obj_addr_on_target, + (unsigned int) gdb_jump_pad_head); + + memcpy (&gdb_jump_pad_head, &buf[IPA_PROTO_FAST_TRACE_JUMP_PAD], 8); + + /* This has been done in agent. We should also set up record for it. */ + memcpy (&fjump_size, &buf[IPA_PROTO_FAST_TRACE_FJUMP_SIZE], 4); + /* Wire it in. */ + tpoint->handle + = set_fast_tracepoint_jump (tpoint->address, insn, fjump_size); + } + + return 0; +} + static void download_tracepoint (struct tracepoint *tpoint) { @@ -5849,42 +6177,6 @@ download_tracepoint (struct tracepoint *tpoint) } -static void -download_tracepoints (void) -{ - CORE_ADDR tpptr = 0, prev_tpptr = 0; - struct tracepoint *tpoint; - - /* Start out empty. */ - write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, 0); - - for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) - { - if (tpoint->type != fast_tracepoint - && tpoint->type != static_tracepoint) - continue; - - prev_tpptr = tpptr; - - download_tracepoint_1 (tpoint); - - tpptr = tpoint->obj_addr_on_target; - - if (tpoint == tracepoints) - { - /* First object in list, set the head pointer in the - inferior. */ - write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, tpptr); - } - else - { - write_inferior_data_ptr (prev_tpptr + offsetof (struct tracepoint, - next), - tpptr); - } - } -} - static void download_trace_state_variables (void) { @@ -6137,7 +6429,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 @@ -6349,7 +6642,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"); @@ -6436,7 +6729,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) { @@ -6480,17 +6773,17 @@ static struct ltt_available_probe gdb_ust_probe = synchronization. */ static int -run_inferior_command (char *cmd) +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); pause_all (0); uninsert_all_breakpoints (); - err = agent_run_command (pid, (const char *) cmd); + err = agent_run_command (pid, (const char *) cmd, len); reinsert_all_breakpoints (); unpause_all (0); @@ -6565,13 +6858,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) { @@ -6579,11 +6873,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; } @@ -6636,7 +6930,7 @@ cstr_to_hexstr (const char *str) { int len = strlen (str); char *hexstr = xmalloc (len * 2 + 1); - convert_int_to_ascii ((gdb_byte *) str, hexstr, len); + bin2hex ((gdb_byte *) str, hexstr, len); return hexstr; } @@ -6812,6 +7106,13 @@ gdb_ust_init (void) #endif /* HAVE_UST */ #include +#include + +static void +gdb_agent_remove_socket (void) +{ + unlink (agent_socket_name); +} /* Helper thread of agent. */ @@ -6820,6 +7121,8 @@ gdb_agent_helper_thread (void *arg) { int listen_fd; + atexit (gdb_agent_remove_socket); + while (1) { listen_fd = gdb_agent_socket_init (); @@ -6840,6 +7143,7 @@ gdb_agent_helper_thread (void *arg) int fd; char buf[1]; int ret; + int stop_loop = 0; tmp = sizeof (sockaddr); @@ -6872,8 +7176,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); } @@ -6905,6 +7213,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); + } } } @@ -7002,10 +7324,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