Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.462
diff -p -r1.462 NEWS
*** NEWS 28 Oct 2011 14:48:36 -0000 1.462
--- NEWS 29 Oct 2011 00:37:56 -0000
***************
*** 13,18 ****
--- 13,23 ----
watchpoints are slower than real hardware watchpoints but are
significantly faster than gdb software watchpoints.
+ qTMinFTPILen
+
+ Query the minimum length of instruction at which a fast tracepoint may
+ be placed.
+
* Python scripting
** The register_pretty_printer function in module gdb.printing now takes
Index: i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.339
diff -p -r1.339 i386-tdep.c
*** i386-tdep.c 11 Oct 2011 19:08:58 -0000 1.339
--- i386-tdep.c 29 Oct 2011 00:37:56 -0000
*************** static const int i386_record_regmap[] =
*** 7109,7118 ****
};
/* Check that the given address appears suitable for a fast
! tracepoint, which on x86 means that we need an instruction of at
least 5 bytes, so that we can overwrite it with a 4-byte-offset
jump and not have to worry about program jumps to an address in the
! middle of the tracepoint jump. Returns 1 if OK, and writes a size
of instruction to replace, and 0 if not, plus an explanatory
string. */
--- 7109,7120 ----
};
/* Check that the given address appears suitable for a fast
! tracepoint, which on x86-64 means that we need an instruction of at
least 5 bytes, so that we can overwrite it with a 4-byte-offset
jump and not have to worry about program jumps to an address in the
! middle of the tracepoint jump. On x86, it may be possible to use
! 4-byte jumps with a 2-byte offset to a trampoline located in the
! bottom 64 KiB of memory. Returns 1 if OK, and writes a size
of instruction to replace, and 0 if not, plus an explanatory
string. */
*************** i386_fast_tracepoint_valid_at (struct gd
*** 7123,7132 ****
int len, jumplen;
static struct ui_file *gdb_null = NULL;
! /* This is based on the target agent using a 4-byte relative jump.
! Alternate future possibilities include 8-byte offset for x86-84,
! or 3-byte jumps if the program has trampoline space close by. */
! jumplen = 5;
/* Dummy file descriptor for the disassembler. */
if (!gdb_null)
--- 7125,7150 ----
int len, jumplen;
static struct ui_file *gdb_null = NULL;
! /* Ask the target for the minimum instruction length supported. */
! jumplen = target_get_min_fast_tracepoint_insn_len ();
!
! if (jumplen < 0)
! {
! /* If the target does not support the get_min_fast_tracepoint_insn_len
! operation, assume that fast tracepoints will always be implemented
! using 4-byte relative jumps on both x86 and x86-64. */
! jumplen = 5;
! }
! else if (jumplen == 0)
! {
! /* If the target does support get_min_fast_tracepoint_insn_len but
! returns zero, then the IPA has not loaded yet. In this case,
! we optimistically assume that truncated 2-byte relative jumps
! will be available on x86, and compensate later if this assumption
! turns out to be incorrect. On x86-64 architectures, 4-byte relative
! jumps will always be used. */
! jumplen = (register_size (gdbarch, 0) == 8) ? 5 : 4;
! }
/* Dummy file descriptor for the disassembler. */
if (!gdb_null)
*************** i386_fast_tracepoint_valid_at (struct gd
*** 7134,7139 ****
--- 7152,7160 ----
/* Check for fit. */
len = gdb_print_insn (gdbarch, addr, gdb_null, NULL);
+ if (isize)
+ *isize = len;
+
if (len < jumplen)
{
/* Return a bit of target-specific detail to add to the caller's
*************** i386_fast_tracepoint_valid_at (struct gd
*** 7144,7155 ****
len, jumplen);
return 0;
}
!
! if (isize)
! *isize = len;
! if (msg)
! *msg = NULL;
! return 1;
}
static int
--- 7165,7176 ----
len, jumplen);
return 0;
}
! else
! {
! if (msg)
! *msg = NULL;
! return 1;
! }
}
static int
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.465
diff -p -r1.465 remote.c
*** remote.c 13 Oct 2011 13:15:16 -0000 1.465
--- remote.c 29 Oct 2011 00:37:56 -0000
*************** remote_write_bytes_aux (const char *head
*** 6338,6344 ****
if (todo <= 0)
internal_error (__FILE__, __LINE__,
! _("minumum packet size too small to write data"));
/* If we already need another packet, then try to align the end
of this packet to a useful boundary. */
--- 6338,6344 ----
if (todo <= 0)
internal_error (__FILE__, __LINE__,
! _("minimum packet size too small to write data"));
/* If we already need another packet, then try to align the end
of this packet to a useful boundary. */
*************** remote_download_tracepoint (struct break
*** 9859,9869 ****
tpaddr, &isize, NULL))
sprintf (buf + strlen (buf), ":F%x", isize);
else
! /* If it passed validation at definition but fails now,
! something is very wrong. */
! internal_error (__FILE__, __LINE__,
! _("Fast tracepoint not "
! "valid during download"));
}
else
/* Fast tracepoints are functionally identical to regular
--- 9859,9868 ----
tpaddr, &isize, NULL))
sprintf (buf + strlen (buf), ":F%x", isize);
else
! warning (_("Target does not support fast tracepoints at "
! "%d-byte long instructions, downloading %d as "
! "regular tracepoint."),
! isize, b->number);
}
else
/* Fast tracepoints are functionally identical to regular
*************** remote_traceframe_info (void)
*** 10390,10395 ****
--- 10389,10419 ----
return NULL;
}
+ /* Handle the qTMinFTPILen packet. Returns the minimum length of instruction
+ on which a fast tracepoint may be placed. Returns -1 if the packet is not
+ supported, and 0 if the minimum instruction length is unknown. */
+
+ static int
+ remote_get_min_fast_tracepoint_insn_len (void)
+ {
+ struct remote_state *rs = get_remote_state ();
+ char *reply;
+
+ sprintf (rs->buf, "qTMinFTPILen");
+ putpkt (rs->buf);
+ reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (*reply == '\0')
+ return -1;
+ else
+ {
+ ULONGEST min_insn_len;
+
+ unpack_varlen_hex (reply, &min_insn_len);
+
+ return (int) min_insn_len;
+ }
+ }
+
static void
init_remote_ops (void)
{
*************** Specify the serial device it is connecte
*** 10477,10482 ****
--- 10501,10507 ----
remote_ops.to_upload_trace_state_variables
= remote_upload_trace_state_variables;
remote_ops.to_get_raw_trace_data = remote_get_raw_trace_data;
+ remote_ops.to_get_min_fast_tracepoint_insn_len = remote_get_min_fast_tracepoint_insn_len;
remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
remote_ops.to_core_of_thread = remote_core_of_thread;
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.286
diff -p -r1.286 target.c
*** target.c 7 Oct 2011 12:06:46 -0000 1.286
--- target.c 29 Oct 2011 00:37:56 -0000
*************** update_current_target (void)
*** 687,692 ****
--- 687,693 ----
INHERIT (to_upload_tracepoints, t);
INHERIT (to_upload_trace_state_variables, t);
INHERIT (to_get_raw_trace_data, t);
+ INHERIT (to_get_min_fast_tracepoint_insn_len, t);
INHERIT (to_set_disconnected_tracing, t);
INHERIT (to_set_circular_trace_buffer, t);
INHERIT (to_get_tib_address, t);
*************** update_current_target (void)
*** 885,890 ****
--- 886,894 ----
de_fault (to_get_raw_trace_data,
(LONGEST (*) (gdb_byte *, ULONGEST, LONGEST))
tcomplain);
+ de_fault (to_get_min_fast_tracepoint_insn_len,
+ (int (*) (void))
+ return_minus_one);
de_fault (to_set_disconnected_tracing,
(void (*) (int))
target_ignore);
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.214
diff -p -r1.214 target.h
*** target.h 28 Oct 2011 18:29:59 -0000 1.214
--- target.h 29 Oct 2011 00:37:56 -0000
*************** struct target_ops
*** 731,736 ****
--- 731,742 ----
LONGEST (*to_get_raw_trace_data) (gdb_byte *buf,
ULONGEST offset, LONGEST len);
+ /* Get the minimum length of instruction on which a fast tracepoint
+ may be set on the target. If this operation is unsupported,
+ return -1. If for some reason the minimum length cannot be
+ determined, return 0. */
+ int (*to_get_min_fast_tracepoint_insn_len) (void);
+
/* Set the target's tracing behavior in response to unexpected
disconnection - set VAL to 1 to keep tracing, 0 to stop. */
void (*to_set_disconnected_tracing) (int val);
*************** extern int target_search_memory (CORE_AD
*** 1510,1515 ****
--- 1516,1524 ----
#define target_get_raw_trace_data(buf,offset,len) \
(*current_target.to_get_raw_trace_data) ((buf), (offset), (len))
+ #define target_get_min_fast_tracepoint_insn_len() \
+ (*current_target.to_get_min_fast_tracepoint_insn_len) ()
+
#define target_set_disconnected_tracing(val) \
(*current_target.to_set_disconnected_tracing) (val)
Index: gdbserver/linux-i386-ipa.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-i386-ipa.c,v
retrieving revision 1.5
diff -p -r1.5 linux-i386-ipa.c
*** gdbserver/linux-i386-ipa.c 16 May 2011 15:59:45 -0000 1.5
--- gdbserver/linux-i386-ipa.c 29 Oct 2011 00:37:56 -0000
***************
*** 19,24 ****
--- 19,26 ----
along with this program. If not, see . */
#include "server.h"
+ #include
+ #include
/* GDB register numbers. */
*************** supply_static_tracepoint_registers (stru
*** 191,198 ****
--- 193,247 ----
may use it proper at some point. */
const char *gdbserver_xmltarget;
+ /* Attempt to allocate memory for trampolines in the first 64 KiB of
+ memory to enable smaller jump patches. */
+
+ static void
+ initialize_fast_tracepoint_trampoline_buffer (void)
+ {
+ const CORE_ADDR buffer_end = 64 * 1024;
+ char buf[100];
+ CORE_ADDR mmap_min_addr = buffer_end + 1;
+ ULONGEST buffer_size;
+ FILE *f = fopen ("/proc/sys/vm/mmap_min_addr", "r");
+
+ if (!f)
+ {
+ snprintf (buf, sizeof (buf), "mmap_min_addr open failed: %s",
+ strerror (errno));
+ set_trampoline_buffer_space (0, 0, buf);
+ return;
+ }
+
+ if (fgets (buf, 100, f))
+ sscanf (buf, "%llu", &mmap_min_addr);
+
+ fclose (f);
+
+ buffer_size = buffer_end - mmap_min_addr;
+
+ /* Ensure that the buffer will be at least 1 KiB in size (i.e. enough
+ space for over 200 fast tracepoints). */
+ if (buffer_size >= 1024)
+ {
+ if (mmap ((void *) (uintptr_t) mmap_min_addr, buffer_size,
+ PROT_READ | PROT_EXEC | PROT_WRITE,
+ MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0)
+ != MAP_FAILED)
+ set_trampoline_buffer_space (mmap_min_addr, buffer_end, NULL);
+ else
+ {
+ snprintf (buf, 99, "low-64K-buffer mmap() failed: %s",
+ strerror (errno));
+ set_trampoline_buffer_space (0, 0, buf);
+ }
+ }
+ }
+
void
initialize_low_tracepoint (void)
{
init_registers_i386_linux ();
+ initialize_fast_tracepoint_trampoline_buffer ();
}
Index: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.178
diff -p -r1.178 linux-low.c
*** gdbserver/linux-low.c 7 Oct 2011 12:06:48 -0000 1.178
--- gdbserver/linux-low.c 29 Oct 2011 00:37:57 -0000
*************** linux_install_fast_tracepoint_jump_pad (
*** 4933,4947 ****
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end)
{
return (*the_low_target.install_fast_tracepoint_jump_pad)
(tpoint, tpaddr, collector, lockaddr, orig_size,
! jump_entry, jjump_pad_insn, jjump_pad_insn_size,
! adjusted_insn_addr, adjusted_insn_addr_end);
}
static struct emit_ops *
--- 4933,4952 ----
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
+ CORE_ADDR *trampoline,
+ ULONGEST *trampoline_size,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end,
! char *err)
{
return (*the_low_target.install_fast_tracepoint_jump_pad)
(tpoint, tpaddr, collector, lockaddr, orig_size,
! jump_entry, trampoline, trampoline_size,
! jjump_pad_insn, jjump_pad_insn_size,
! adjusted_insn_addr, adjusted_insn_addr_end,
! err);
}
static struct emit_ops *
*************** linux_emit_ops (void)
*** 4953,4958 ****
--- 4958,4969 ----
return NULL;
}
+ static int
+ linux_get_min_fast_tracepoint_insn_len (void)
+ {
+ return (*the_low_target.get_min_fast_tracepoint_insn_len) ();
+ }
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_attach,
*************** static struct target_ops linux_target_op
*** 5014,5019 ****
--- 5025,5031 ----
linux_install_fast_tracepoint_jump_pad,
linux_emit_ops,
linux_supports_disable_randomization,
+ linux_get_min_fast_tracepoint_insn_len,
};
static void
Index: gdbserver/linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.47
diff -p -r1.47 linux-low.h
*** gdbserver/linux-low.h 1 Jan 2011 15:33:24 -0000 1.47
--- gdbserver/linux-low.h 29 Oct 2011 00:37:57 -0000
*************** struct linux_target_ops
*** 132,145 ****
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end);
/* Return the bytecode operations vector for the current inferior.
Returns NULL if bytecode compilation is not supported. */
struct emit_ops *(*emit_ops) (void);
};
extern struct linux_target_ops the_low_target;
--- 132,153 ----
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
+ CORE_ADDR *trampoline,
+ ULONGEST *trampoline_size,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end,
! char *err);
/* Return the bytecode operations vector for the current inferior.
Returns NULL if bytecode compilation is not supported. */
struct emit_ops *(*emit_ops) (void);
+
+ /* Return the minimum length of an instruction that can be safely overwritten
+ for use as a fast tracepoint. */
+ int (*get_min_fast_tracepoint_insn_len) (void);
+
};
extern struct linux_target_ops the_low_target;
Index: gdbserver/linux-x86-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-x86-low.c,v
retrieving revision 1.30
diff -p -r1.30 linux-x86-low.c
*** gdbserver/linux-x86-low.c 15 Sep 2011 22:54:12 -0000 1.30
--- gdbserver/linux-x86-low.c 29 Oct 2011 00:37:57 -0000
*************** void init_registers_amd64_avx_linux (voi
*** 42,47 ****
--- 42,48 ----
void init_registers_i386_mmx_linux (void);
static unsigned char jump_insn[] = { 0xe9, 0, 0, 0, 0 };
+ static unsigned char small_jump_insn[] = { 0x66, 0xe9, 0, 0 };
/* Backward compatibility for gdb without XML support. */
*************** amd64_install_fast_tracepoint_jump_pad (
*** 1182,1191 ****
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end)
{
unsigned char buf[40];
int i, offset;
--- 1183,1195 ----
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
+ CORE_ADDR *trampoline,
+ ULONGEST *trampoline_size,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end,
! char *err)
{
unsigned char buf[40];
int i, offset;
*************** i386_install_fast_tracepoint_jump_pad (C
*** 1346,1355 ****
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end)
{
unsigned char buf[0x100];
int i, offset;
--- 1350,1362 ----
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
+ CORE_ADDR *trampoline,
+ ULONGEST *trampoline_size,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end,
! char *err)
{
unsigned char buf[0x100];
int i, offset;
*************** i386_install_fast_tracepoint_jump_pad (C
*** 1455,1461 ****
buf[i++] = 0x0f; /* pop %fs */
buf[i++] = 0xa1;
buf[i++] = 0x07; /* pop %es */
! buf[i++] = 0x1f; /* pop %de */
buf[i++] = 0x9d; /* popf */
buf[i++] = 0x83; /* add $0x4,%esp (pop of tpaddr aka $pc) */
buf[i++] = 0xc4;
--- 1462,1468 ----
buf[i++] = 0x0f; /* pop %fs */
buf[i++] = 0xa1;
buf[i++] = 0x07; /* pop %es */
! buf[i++] = 0x1f; /* pop %ds */
buf[i++] = 0x9d; /* popf */
buf[i++] = 0x83; /* add $0x4,%esp (pop of tpaddr aka $pc) */
buf[i++] = 0xc4;
*************** i386_install_fast_tracepoint_jump_pad (C
*** 1479,1489 ****
is always done last (by our caller actually), so that we can
install fast tracepoints with threads running. This relies on
the agent's atomic write support. */
! offset = *jump_entry - (tpaddr + sizeof (jump_insn));
! memcpy (buf, jump_insn, sizeof (jump_insn));
! memcpy (buf + 1, &offset, 4);
! memcpy (jjump_pad_insn, buf, sizeof (jump_insn));
! *jjump_pad_insn_size = sizeof (jump_insn);
/* Return the end address of our pad. */
*jump_entry = buildaddr;
--- 1486,1525 ----
is always done last (by our caller actually), so that we can
install fast tracepoints with threads running. This relies on
the agent's atomic write support. */
! if (orig_size == 4)
! {
! /* Create a trampoline. */
! *trampoline_size = sizeof (jump_insn);
! if (!claim_trampoline_space (*trampoline_size, trampoline))
! {
! /* No trampoline space available. */
! strcpy (err,
! "E.Cannot allocate trampoline space needed for fast "
! "tracepoints on 4-byte instructions.");
! return 1;
! }
!
! offset = *jump_entry - (*trampoline + sizeof (jump_insn));
! memcpy (buf, jump_insn, sizeof (jump_insn));
! memcpy (buf + 1, &offset, 4);
! write_inferior_memory (*trampoline, buf, sizeof (jump_insn));
!
! /* Use a 16-bit relative jump instruction to jump to the trampoline. */
! offset = (*trampoline - (tpaddr + sizeof (small_jump_insn))) & 0xffff;
! memcpy (buf, small_jump_insn, sizeof (small_jump_insn));
! memcpy (buf + 2, &offset, 2);
! memcpy (jjump_pad_insn, buf, sizeof (small_jump_insn));
! *jjump_pad_insn_size = sizeof (small_jump_insn);
! }
! else
! {
! /* Else use a 32-bit relative jump instruction. */
! offset = *jump_entry - (tpaddr + sizeof (jump_insn));
! memcpy (buf, jump_insn, sizeof (jump_insn));
! memcpy (buf + 1, &offset, 4);
! memcpy (jjump_pad_insn, buf, sizeof (jump_insn));
! *jjump_pad_insn_size = sizeof (jump_insn);
! }
/* Return the end address of our pad. */
*jump_entry = buildaddr;
*************** x86_install_fast_tracepoint_jump_pad (CO
*** 1497,1525 ****
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end)
{
#ifdef __x86_64__
if (register_size (0) == 8)
return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr,
collector, lockaddr,
orig_size, jump_entry,
jjump_pad_insn,
jjump_pad_insn_size,
adjusted_insn_addr,
! adjusted_insn_addr_end);
#endif
return i386_install_fast_tracepoint_jump_pad (tpoint, tpaddr,
collector, lockaddr,
orig_size, jump_entry,
jjump_pad_insn,
jjump_pad_insn_size,
adjusted_insn_addr,
! adjusted_insn_addr_end);
}
static void
--- 1533,1610 ----
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
+ CORE_ADDR *trampoline,
+ ULONGEST *trampoline_size,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end,
! char *err)
{
#ifdef __x86_64__
if (register_size (0) == 8)
return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr,
collector, lockaddr,
orig_size, jump_entry,
+ trampoline, trampoline_size,
jjump_pad_insn,
jjump_pad_insn_size,
adjusted_insn_addr,
! adjusted_insn_addr_end,
! err);
#endif
return i386_install_fast_tracepoint_jump_pad (tpoint, tpaddr,
collector, lockaddr,
orig_size, jump_entry,
+ trampoline, trampoline_size,
jjump_pad_insn,
jjump_pad_insn_size,
adjusted_insn_addr,
! adjusted_insn_addr_end,
! err);
! }
!
! /* Return the minimum instruction length for fast tracepoints on x86/x86-64
! architectures. */
!
! static int
! x86_get_min_fast_tracepoint_insn_len (void)
! {
! static int warned_about_fast_tracepoints = 0;
!
! #ifdef __x86_64__
! /* On x86-64, 5-byte jump instructions with a 4-byte offset are always
! used for fast tracepoints. */
! if (register_size (0) == 8)
! return 5;
! #endif
!
! if (in_process_agent_loaded ())
! {
! char mybuf[100];
!
! /* On x86, if trampolines are available, then 4-byte jump instructions
! with a 2-byte offset may be used, otherwise 5-byte jump instructions
! with a 4-byte offset are used instead. */
! if (have_fast_tracepoint_trampoline_buffer (mybuf))
! return 4;
! else
! {
! if (!warned_about_fast_tracepoints)
! {
! warning ("4-byte fast tracepoints not available; %s\n", mybuf);
! warned_about_fast_tracepoints = 1;
! }
! return 5;
! }
! }
! else
! {
! /* Indicate that the minimum length is currently unknown since the IPA
! has not loaded yet. */
! return 0;
! }
}
static void
*************** struct linux_target_ops the_low_target =
*** 2873,2877 ****
x86_supports_tracepoints,
x86_get_thread_area,
x86_install_fast_tracepoint_jump_pad,
! x86_emit_ops
};
--- 2958,2963 ----
x86_supports_tracepoints,
x86_get_thread_area,
x86_install_fast_tracepoint_jump_pad,
! x86_emit_ops,
! x86_get_min_fast_tracepoint_insn_len,
};
Index: gdbserver/server.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.h,v
retrieving revision 1.87
diff -p -r1.87 server.h
*** gdbserver/server.h 7 Oct 2011 12:06:48 -0000 1.87
--- gdbserver/server.h 29 Oct 2011 00:37:57 -0000
*************** void supply_fast_tracepoint_registers (s
*** 494,501 ****
--- 494,506 ----
void supply_static_tracepoint_registers (struct regcache *regcache,
const unsigned char *regs,
CORE_ADDR pc);
+ void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end,
+ char *errmsg);
#else
void stop_tracing (void);
+
+ int claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline);
+ int have_fast_tracepoint_trampoline_buffer (char *msgbuf);
#endif
/* Bytecode compilation function vector. */
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.57
diff -p -r1.57 target.h
*** gdbserver/target.h 7 Oct 2011 12:06:48 -0000 1.57
--- gdbserver/target.h 29 Oct 2011 00:37:57 -0000
*************** struct target_ops
*** 359,378 ****
pad lock object. ORIG_SIZE is the size in bytes of the
instruction at TPADDR. JUMP_ENTRY points to the address of the
jump pad entry, and on return holds the address past the end of
! the created jump pad. JJUMP_PAD_INSN is a buffer containing a
! copy of the instruction at TPADDR. ADJUST_INSN_ADDR and
! ADJUST_INSN_ADDR_END are output parameters that return the
! address range where the instruction at TPADDR was relocated
! to. */
int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr,
CORE_ADDR collector,
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end);
/* Return the bytecode operations vector for the current inferior.
Returns NULL if bytecode compilation is not supported. */
--- 359,384 ----
pad lock object. ORIG_SIZE is the size in bytes of the
instruction at TPADDR. JUMP_ENTRY points to the address of the
jump pad entry, and on return holds the address past the end of
! the created jump pad. If a trampoline is created by the function,
! then TRAMPOLINE and TRAMPOLINE_SIZE return the address and size of
! the trampoline, else they remain unchanged. JJUMP_PAD_INSN is a
! buffer containing a copy of the instruction at TPADDR.
! ADJUST_INSN_ADDR and ADJUST_INSN_ADDR_END are output parameters that
! return the address range where the instruction at TPADDR was relocated
! to. If an error occurs, the ERR may be used to pass on an error
! message. */
int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr,
CORE_ADDR collector,
CORE_ADDR lockaddr,
ULONGEST orig_size,
CORE_ADDR *jump_entry,
+ CORE_ADDR *trampoline,
+ ULONGEST *trampoline_size,
unsigned char *jjump_pad_insn,
ULONGEST *jjump_pad_insn_size,
CORE_ADDR *adjusted_insn_addr,
! CORE_ADDR *adjusted_insn_addr_end,
! char *err);
/* Return the bytecode operations vector for the current inferior.
Returns NULL if bytecode compilation is not supported. */
*************** struct target_ops
*** 380,385 ****
--- 386,395 ----
/* Returns true if the target supports disabling randomization. */
int (*supports_disable_randomization) (void);
+
+ /* Return the minimum length of an instruction that can be safely overwritten
+ for use as a fast tracepoint. */
+ int (*get_min_fast_tracepoint_insn_len) (void);
};
extern struct target_ops *the_target;
*************** void set_target_ops (struct target_ops *
*** 437,442 ****
--- 447,456 ----
#define target_supports_fast_tracepoints() \
(the_target->install_fast_tracepoint_jump_pad != NULL)
+ #define target_get_min_fast_tracepoint_insn_len() \
+ (the_target->get_min_fast_tracepoint_insn_len \
+ ? (*the_target->get_min_fast_tracepoint_insn_len) () : 0)
+
#define thread_stopped(thread) \
(*the_target->thread_stopped) (thread)
*************** void set_target_ops (struct target_ops *
*** 471,487 ****
#define install_fast_tracepoint_jump_pad(tpoint, tpaddr, \
collector, lockaddr, \
orig_size, \
! jump_entry, jjump_pad_insn, \
jjump_pad_insn_size, \
adjusted_insn_addr, \
! adjusted_insn_addr_end) \
(*the_target->install_fast_tracepoint_jump_pad) (tpoint, tpaddr, \
collector,lockaddr, \
orig_size, jump_entry, \
jjump_pad_insn, \
jjump_pad_insn_size, \
adjusted_insn_addr, \
! adjusted_insn_addr_end)
#define target_emit_ops() \
(the_target->emit_ops ? (*the_target->emit_ops) () : NULL)
--- 485,507 ----
#define install_fast_tracepoint_jump_pad(tpoint, tpaddr, \
collector, lockaddr, \
orig_size, \
! jump_entry, \
! trampoline, trampoline_size, \
! jjump_pad_insn, \
jjump_pad_insn_size, \
adjusted_insn_addr, \
! adjusted_insn_addr_end, \
! err) \
(*the_target->install_fast_tracepoint_jump_pad) (tpoint, tpaddr, \
collector,lockaddr, \
orig_size, jump_entry, \
+ trampoline, \
+ trampoline_size, \
jjump_pad_insn, \
jjump_pad_insn_size, \
adjusted_insn_addr, \
! adjusted_insn_addr_end, \
! err)
#define target_emit_ops() \
(the_target->emit_ops ? (*the_target->emit_ops) () : NULL)
Index: gdbserver/tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/tracepoint.c,v
retrieving revision 1.27
diff -p -r1.27 tracepoint.c
*** gdbserver/tracepoint.c 15 Sep 2011 22:54:13 -0000 1.27
--- gdbserver/tracepoint.c 29 Oct 2011 00:37:57 -0000
*************** trace_vdebug (const char *fmt, ...)
*** 110,115 ****
--- 110,118 ----
# define gdb_tp_heap_buffer gdb_agent_gdb_tp_heap_buffer
# define gdb_jump_pad_buffer gdb_agent_gdb_jump_pad_buffer
# define gdb_jump_pad_buffer_end gdb_agent_gdb_jump_pad_buffer_end
+ # define gdb_trampoline_buffer gdb_agent_gdb_trampoline_buffer
+ # define gdb_trampoline_buffer_end gdb_agent_gdb_trampoline_buffer_end
+ # define gdb_trampoline_buffer_error gdb_agent_gdb_trampoline_buffer_error
# define collecting gdb_agent_collecting
# define gdb_collect gdb_agent_gdb_collect
# define stop_tracing gdb_agent_stop_tracing
*************** struct ipa_sym_addresses
*** 148,153 ****
--- 151,159 ----
CORE_ADDR addr_gdb_tp_heap_buffer;
CORE_ADDR addr_gdb_jump_pad_buffer;
CORE_ADDR addr_gdb_jump_pad_buffer_end;
+ CORE_ADDR addr_gdb_trampoline_buffer;
+ 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_stop_tracing;
*************** static struct
*** 192,197 ****
--- 198,206 ----
IPA_SYM(gdb_tp_heap_buffer),
IPA_SYM(gdb_jump_pad_buffer),
IPA_SYM(gdb_jump_pad_buffer_end),
+ IPA_SYM(gdb_trampoline_buffer),
+ IPA_SYM(gdb_trampoline_buffer_end),
+ IPA_SYM(gdb_trampoline_buffer_error),
IPA_SYM(collecting),
IPA_SYM(gdb_collect),
IPA_SYM(stop_tracing),
*************** struct tracepoint
*** 658,663 ****
--- 667,678 ----
CORE_ADDR jump_pad;
CORE_ADDR jump_pad_end;
+ /* The address range of the piece of the trampoline buffer that was
+ assigned to this fast tracepoint. (_end is actually one byte
+ past the end). */
+ CORE_ADDR trampoline;
+ CORE_ADDR trampoline_end;
+
/* The list of actions to take while in a stepping loop. These
fields are only valid for patch-based tracepoints. */
int num_step_actions;
*************** claim_jump_space (ULONGEST used)
*** 2654,2659 ****
--- 2669,2746 ----
gdb_jump_pad_head += used;
}
+ static CORE_ADDR trampoline_buffer_head = 0;
+ static CORE_ADDR trampoline_buffer_tail;
+
+ /* Reserve USED bytes from the trampoline buffer and return the
+ address of the start of the reserved space in TRAMPOLINE. Returns
+ non-zero if the space is successfully claimed. */
+
+ int
+ claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline)
+ {
+ if (!trampoline_buffer_head)
+ {
+ if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer,
+ &trampoline_buffer_tail))
+ {
+ fatal ("error extracting trampoline_buffer");
+ return 0;
+ }
+
+ if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
+ &trampoline_buffer_head))
+ {
+ fatal ("error extracting trampoline_buffer_end");
+ return 0;
+ }
+ }
+
+ /* Start claiming space from the top of the trampoline space. If
+ the space is located at the bottom of the virtual address space,
+ this reduces the possibility that corruption will occur if a null
+ pointer is used to write to memory. */
+ if (trampoline_buffer_head - trampoline_buffer_tail < used)
+ {
+ trace_debug ("claim_trampoline_space failed to reserve %s bytes",
+ pulongest (used));
+ return 0;
+ }
+
+ trampoline_buffer_head -= used;
+
+ trace_debug ("claim_trampoline_space reserves %s bytes at %s",
+ pulongest (used), paddress (trampoline_buffer_head));
+
+ *trampoline = trampoline_buffer_head;
+ return 1;
+ }
+
+ /* Returns non-zero if there is space allocated for use in trampolines
+ for fast tracepoints. */
+
+ int
+ have_fast_tracepoint_trampoline_buffer (char *buf)
+ {
+ CORE_ADDR trampoline_end, errbuf;
+
+ if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
+ &trampoline_end))
+ fatal ("error extracting trampoline_buffer_end");
+
+ if (buf)
+ {
+ buf[0] = '\0';
+ if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_error,
+ &errbuf))
+ fatal ("error extracting errbuf");
+
+ read_inferior_memory (errbuf, (unsigned char *) buf, 100);
+ }
+
+ return trampoline_end != 0;
+ }
+
/* Sort tracepoints by PC, using a bubble sort. */
static void
*************** cmd_qtstart (char *packet)
*** 2818,2835 ****
fjump_size);
tpoint->jump_pad = prev_ftpoint->jump_pad;
tpoint->jump_pad_end = prev_ftpoint->jump_pad_end;
tpoint->adjusted_insn_addr = prev_ftpoint->adjusted_insn_addr;
tpoint->adjusted_insn_addr_end
= prev_ftpoint->adjusted_insn_addr_end;
}
else
{
! CORE_ADDR jentry;
int err = 0;
prev_ftpoint = NULL;
jentry = jump_entry = get_jump_space_head ();
/* Install the jump pad. */
err = install_fast_tracepoint_jump_pad
--- 2905,2934 ----
fjump_size);
tpoint->jump_pad = prev_ftpoint->jump_pad;
tpoint->jump_pad_end = prev_ftpoint->jump_pad_end;
+ tpoint->trampoline = prev_ftpoint->trampoline;
+ tpoint->trampoline_end = prev_ftpoint->trampoline_end;
tpoint->adjusted_insn_addr = prev_ftpoint->adjusted_insn_addr;
tpoint->adjusted_insn_addr_end
= prev_ftpoint->adjusted_insn_addr_end;
}
else
{
! CORE_ADDR jentry, trampoline;
! ULONGEST trampoline_size;
int err = 0;
+ if (tpoint->orig_size < target_get_min_fast_tracepoint_insn_len ())
+ {
+ trace_debug ("Requested a fast tracepoint on an instruction "
+ "that is of less than the minimum length.");
+ break;
+ }
+
prev_ftpoint = NULL;
jentry = jump_entry = get_jump_space_head ();
+ trampoline = 0;
+ trampoline_size = 0;
/* Install the jump pad. */
err = install_fast_tracepoint_jump_pad
*************** cmd_qtstart (char *packet)
*** 2839,2847 ****
ipa_sym_addrs.addr_collecting,
tpoint->orig_size,
&jentry,
fjump, &fjump_size,
&tpoint->adjusted_insn_addr,
! &tpoint->adjusted_insn_addr_end);
/* Wire it in. */
if (!err)
--- 2938,2948 ----
ipa_sym_addrs.addr_collecting,
tpoint->orig_size,
&jentry,
+ &trampoline, &trampoline_size,
fjump, &fjump_size,
&tpoint->adjusted_insn_addr,
! &tpoint->adjusted_insn_addr_end,
! packet);
/* Wire it in. */
if (!err)
*************** cmd_qtstart (char *packet)
*** 2852,2857 ****
--- 2953,2960 ----
{
tpoint->jump_pad = jump_entry;
tpoint->jump_pad_end = jentry;
+ tpoint->trampoline = trampoline;
+ tpoint->trampoline_end = trampoline + trampoline_size;
/* Pad to 8-byte alignment. */
jentry = ((jentry + 7) & ~0x7);
*************** cmd_qtstmat (char *packet)
*** 3435,3440 ****
--- 3538,3552 ----
run_inferior_command (packet);
}
+ /* Return the minimum instruction size needed for fast tracepoints as a
+ hexadecimal number. */
+
+ static void
+ cmd_qtminftpilen (char *packet)
+ {
+ sprintf (packet, "%x", target_get_min_fast_tracepoint_insn_len ());
+ }
+
/* Respond to qTBuffer packet with a block of raw data from the trace
buffer. GDB may ask for a lot, but we are allowed to reply with
only as much as will fit within packet limits or whatever. */
*************** handle_tracepoint_query (char *packet)
*** 3631,3636 ****
--- 3743,3753 ----
cmd_qtstmat (packet);
return 1;
}
+ else if (strcmp ("qTMinFTPILen", packet) == 0)
+ {
+ cmd_qtminftpilen (packet);
+ return 1;
+ }
return 0;
}
*************** fast_tracepoint_from_jump_pad_address (C
*** 5180,5185 ****
--- 5297,5319 ----
return NULL;
}
+ /* Return the first fast tracepoint whose trampoline contains PC. */
+
+ static struct tracepoint *
+ fast_tracepoint_from_trampoline_address (CORE_ADDR pc)
+ {
+ struct tracepoint *tpoint;
+
+ for (tpoint = tracepoints; tpoint; tpoint = tpoint->next)
+ {
+ if (tpoint->type == fast_tracepoint
+ && tpoint->trampoline <= pc && pc < tpoint->trampoline_end)
+ return tpoint;
+ }
+
+ return NULL;
+ }
+
/* Return GDBserver's tracepoint that matches the IP Agent's
tracepoint object that lives at IPA_TPOINT_OBJ in the IP Agent's
address space. */
*************** fast_tracepoint_collecting (CORE_ADDR th
*** 5242,5247 ****
--- 5376,5383 ----
{
CORE_ADDR ipa_collecting;
CORE_ADDR ipa_gdb_jump_pad_buffer, ipa_gdb_jump_pad_buffer_end;
+ CORE_ADDR ipa_gdb_trampoline_buffer;
+ CORE_ADDR ipa_gdb_trampoline_buffer_end;
struct tracepoint *tpoint;
int needs_breakpoint;
*************** fast_tracepoint_collecting (CORE_ADDR th
*** 5280,5285 ****
--- 5416,5428 ----
&ipa_gdb_jump_pad_buffer_end))
fatal ("error extracting `gdb_jump_pad_buffer_end'");
+ if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer,
+ &ipa_gdb_trampoline_buffer))
+ fatal ("error extracting `gdb_trampoline_buffer'");
+ if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
+ &ipa_gdb_trampoline_buffer_end))
+ fatal ("error extracting `gdb_trampoline_buffer_end'");
+
if (ipa_gdb_jump_pad_buffer <= stop_pc
&& stop_pc < ipa_gdb_jump_pad_buffer_end)
{
*************** fast_tracepoint_collecting (CORE_ADDR th
*** 5308,5313 ****
--- 5451,5480 ----
&& stop_pc < tpoint->adjusted_insn_addr)
needs_breakpoint = 1;
}
+ else if (ipa_gdb_trampoline_buffer <= stop_pc
+ && stop_pc < ipa_gdb_trampoline_buffer_end)
+ {
+ /* We can tell which tracepoint(s) the thread is collecting by
+ matching the trampoline address back to the tracepoint. */
+ tpoint = fast_tracepoint_from_trampoline_address (stop_pc);
+ if (tpoint == NULL)
+ {
+ warning ("in trampoline, but no matching tpoint?");
+ return 0;
+ }
+ else
+ {
+ trace_debug ("in trampoline of tpoint (%d, %s); trampoline(%s, %s)",
+ tpoint->number, paddress (tpoint->address),
+ paddress (tpoint->trampoline),
+ paddress (tpoint->trampoline_end));
+ }
+
+ /* Have not reached jump pad yet, but treat the trampoline as a
+ part of the jump pad that is before the adjusted original
+ instruction. */
+ needs_breakpoint = 1;
+ }
else
{
collecting_t ipa_collecting_obj;
*************** gdb_ust_init (void)
*** 7621,7626 ****
--- 7788,7809 ----
IP_AGENT_EXPORT char *gdb_tp_heap_buffer;
IP_AGENT_EXPORT char *gdb_jump_pad_buffer;
IP_AGENT_EXPORT char *gdb_jump_pad_buffer_end;
+ IP_AGENT_EXPORT char *gdb_trampoline_buffer;
+ IP_AGENT_EXPORT char *gdb_trampoline_buffer_end;
+ IP_AGENT_EXPORT char *gdb_trampoline_buffer_error;
+
+ /* Record the result of getting buffer space for fast tracepoint
+ trampolines. Any error message is copied, since caller may not be
+ using persistent storage. */
+
+ void
+ set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, char *errmsg)
+ {
+ gdb_trampoline_buffer = (char *) (uintptr_t) begin;
+ gdb_trampoline_buffer_end = (char *) (uintptr_t) end;
+ if (errmsg)
+ strncpy (gdb_trampoline_buffer_error, errmsg, 99);
+ }
static void __attribute__ ((constructor))
initialize_tracepoint_ftlib (void)
*************** initialize_tracepoint: mprotect(%p, %d,
*** 7682,7687 ****
--- 7865,7878 ----
gdb_jump_pad_buffer, pagesize * 20, strerror (errno));
}
+ gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0;
+
+ /* It's not a fatal error for something to go wrong with trampoline
+ buffer setup, but it can be mysterious, so create a channel to
+ report back on what went wrong, using a fixed size since we may
+ not be able to allocate space later. */
+ gdb_trampoline_buffer_error = xmalloc (100);
+
initialize_low_tracepoint ();
#endif
}
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.884
diff -p -r1.884 gdb.texinfo
*** doc/gdb.texinfo 28 Oct 2011 14:48:59 -0000 1.884
--- doc/gdb.texinfo 29 Oct 2011 00:37:58 -0000
*************** encoded). @value{GDBN} will continue to
*** 34774,34779 ****
--- 34774,34781 ----
@itemx qTfP
@itemx qTfV
@itemx QTFrame
+ @itemx qTMinFTPILen
+
@xref{Tracepoint Packets}.
@item qThreadExtraInfo,@var{thread-id}
*************** numbers.
*** 35297,35302 ****
--- 35299,35323 ----
Like @samp{QTFrame:range:@var{start}:@var{end}}, but select the first
frame @emph{outside} the given range of addresses (exclusive).
+ @item qTMinFTPILen
+ This packet requests the minimum length of instruction at which a fast
+ tracepoint may be placed.
+
+ Replies:
+
+ @table @samp
+ @item 0
+ The minimum instruction length is currently unknown.
+ @item @var{length}
+ The minimum instruction length is @var{length}, where @var{length} is greater
+ or equal to 1. @var{length} is a hexadecimal number. A reply of 1 means
+ that a fast tracepoint may be placed on any instruction regardless of size.
+ @item E
+ An error has occurred.
+ @item
+ An empty reply indicates that the request is not supported by the stub.
+ @end table
+
@item QTStart
Begin the tracepoint experiment. Begin collecting data from
tracepoint hits in the trace frame buffer. This packet supports the