2011-11-14 Stan Shebs <stan@codesourcery.com>
Kwok Cheung Yeung <kcy@codesourcery.com> * NEWS: Document shorter fast tracepoints and qTMinFTPILen packet. * i386-tdep.c (i386_fast_tracepoint_valid_at): Query target for the minimum instruction size for fast tracepoints. * target.h (struct target_ops): Add new method to_get_min_fast_tracepoint_insn_len. (target_get_min_fast_tracepoint_insn_len): New. * target.c (update_current_target): Set up new target operation. * remote.c (remote_write_bytes_aux): Fix typo. (remote_get_min_fast_tracepoint_insn_len): New. (init_remote_ops): Initialize new field. * gdb.texinfo (Create and Delete Tracepoints): Describe what is needed to get shorter fast tracepoints. (Tracepoint Packets): Document new qTMinFTPILen packet. * linux-x86-low.c (small_jump_insn): New. (i386_install_fast_tracepoint_jump_pad): Add arguments for trampoline and error message, build a trampoline and issue a small jump instruction to it. (x86_install_fast_tracepoint_jump_pad): Add arguments for trampoline and error message. (x86_get_min_fast_tracepoint_insn_len): New. (the_low_target): Add call to x86_get_min_fast_tracepoint_insn_len. * linux-low.h (struct linux_target_ops): Add arguments to install_fast_tracepoint_jump_pad operation, add new operation. * linux-low.c (linux_install_fast_tracepoint_jump_pad): Add arguments. (linux_get_min_fast_tracepoint_insn_len): New function. (linux_target_op): Add new operation. * tracepoint.c (gdb_trampoline_buffer): New IPA variable. (gdb_trampoline_buffer_end): Ditto. (gdb_trampoline_buffer_error): Ditto. (struct ipa_sym_addresses): Add fields for new IPA variables. (symbol_list): Add entries for new IPA variables. (struct tracepoint): Add fields to hold the address range of the trampoline used by the tracepoint. (trampoline_buffer_head): New static variable. (trampoline_buffer_tail): Ditto. (claim_trampoline_space): New function. (have_fast_tracepoint_trampoline_buffer): New function. (clone_fast_tracepoint): Fill in trampoline fields of tracepoint structure. (install_fast_tracepoint): Ditto, also add error buffer argument. (cmd_qtminftpilen): New function. (handle_tracepoint_query): Add response to qTMinFTPILen packet. (fast_tracepoint_from_trampoline_address): New function. (fast_tracepoint_collecting): Handle trampoline as part of jump pad space. (set_trampoline_buffer_space): New function. (initialize_tracepoint): Initialize new IPA variables. * target.h (struct target_ops): Add arguments to install_fast_tracepoint_jump_pad operation, add new get_min_fast_tracepoint_insn_len operation. (target_get_min_fast_tracepoint_insn_len): New. (install_fast_tracepoint_jump_pad): Add arguments. * server.h (IPA_BUFSIZ): Define. * linux-i386-ipa.c: Include extra header files. (initialize_fast_tracepoint_trampoline_buffer): New function. (initialize_low_tracepoint): Call it. * server.h (set_trampoline_buffer_space): Declare. (claim_trampoline_space): Ditto. (have_fast_tracepoint_trampoline_buffer): Ditto. * gdb.trace/ftrace.c: New. * gdb.trace/ftrace.exp: New.
This commit is contained in:
parent
3e05895e9e
commit
405f8e9499
@ -1,3 +1,17 @@
|
||||
2011-11-14 Stan Shebs <stan@codesourcery.com>
|
||||
Kwok Cheung Yeung <kcy@codesourcery.com>
|
||||
|
||||
* NEWS: Document shorter fast tracepoints and qTMinFTPILen packet.
|
||||
* i386-tdep.c (i386_fast_tracepoint_valid_at): Query target for
|
||||
the minimum instruction size for fast tracepoints.
|
||||
* target.h (struct target_ops): Add new method
|
||||
to_get_min_fast_tracepoint_insn_len.
|
||||
(target_get_min_fast_tracepoint_insn_len): New.
|
||||
* target.c (update_current_target): Set up new target operation.
|
||||
* remote.c (remote_write_bytes_aux): Fix typo.
|
||||
(remote_get_min_fast_tracepoint_insn_len): New.
|
||||
(init_remote_ops): Initialize new field.
|
||||
|
||||
2011-11-14 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* tracepoint.c (encode_actions_1): Use the location's gdbarch.
|
||||
|
9
gdb/NEWS
9
gdb/NEWS
@ -134,6 +134,10 @@ collect[/s] EXPRESSIONS
|
||||
begin, assuming that tracepoints will be enabled as needed while the trace
|
||||
is running.
|
||||
|
||||
* Fast tracepoints on 32-bit x86-architectures can now be placed at
|
||||
locations with 4-byte instructions, when they were previously
|
||||
limited to locations with instructions of 5 bytes or longer.
|
||||
|
||||
* New options
|
||||
|
||||
set extended-prompt
|
||||
@ -165,6 +169,11 @@ QTDisable
|
||||
|
||||
Dynamically disable a tracepoint in a started trace experiment.
|
||||
|
||||
qTMinFTPILen
|
||||
|
||||
Query the minimum length of instruction at which a fast tracepoint may
|
||||
be placed.
|
||||
|
||||
* Dcache size (number of lines) and line-size are now runtime-configurable
|
||||
via "set dcache line" and "set dcache line-size" commands.
|
||||
|
||||
|
@ -1,3 +1,10 @@
|
||||
2011-11-14 Stan Shebs <stan@codesourcery.com>
|
||||
Kwok Cheung Yeung <kcy@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (Create and Delete Tracepoints): Describe what is
|
||||
needed to get shorter fast tracepoints.
|
||||
(Tracepoint Packets): Document new qTMinFTPILen packet.
|
||||
|
||||
2011-11-14 Yao Qi <yao@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (Create and Delete Tracepoints): Describe changed
|
||||
|
@ -10378,6 +10378,23 @@ message.
|
||||
@value{GDBN} handles arguments to @code{ftrace} exactly as for
|
||||
@code{trace}.
|
||||
|
||||
On 32-bit x86-architecture systems, fast tracepoints normally need to
|
||||
be placed at an instruction that is 5 bytes or longer, but can be
|
||||
placed at 4-byte instructions if the low 64K of memory of the target
|
||||
program is available to install trampolines. Some Unix-type systems,
|
||||
such as @sc{gnu}/Linux, exclude low addresses from the program's
|
||||
address space; but for instance with the Linux kernel it is possible
|
||||
to let @value{GDBN} use this area by doing a @command{sysctl} command
|
||||
to set the @code{mmap_min_addr} kernel parameter, as in
|
||||
|
||||
@example
|
||||
sudo sysctl -w vm.mmap_min_addr=32768
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
which sets the low address to 32K, which leaves plenty of room for
|
||||
trampolines. The minimum address should be set to a page boundary.
|
||||
|
||||
@item strace @var{location} [ if @var{cond} ]
|
||||
@cindex set static tracepoint
|
||||
@cindex static tracepoints, setting
|
||||
@ -34915,6 +34932,8 @@ encoded). @value{GDBN} will continue to supply the values of symbols
|
||||
@itemx qTfP
|
||||
@itemx qTfV
|
||||
@itemx QTFrame
|
||||
@itemx qTMinFTPILen
|
||||
|
||||
@xref{Tracepoint Packets}.
|
||||
|
||||
@item qThreadExtraInfo,@var{thread-id}
|
||||
@ -35438,6 +35457,30 @@ numbers.
|
||||
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 (@pxref{Set Tracepoints}) may be placed. For instance, on
|
||||
the 32-bit x86 architecture, it is possible to use a 4-byte jump, but
|
||||
it depends on the target system being able to create trampolines in
|
||||
the first 64K of memory, which might or might not be possible for that
|
||||
system. So the reply to this packet will be 4 if it is able to
|
||||
arrange for that.
|
||||
|
||||
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
|
||||
|
@ -1,3 +1,54 @@
|
||||
2011-11-14 Stan Shebs <stan@codesourcery.com>
|
||||
Kwok Cheung Yeung <kcy@codesourcery.com>
|
||||
|
||||
* linux-x86-low.c (small_jump_insn): New.
|
||||
(i386_install_fast_tracepoint_jump_pad): Add arguments for
|
||||
trampoline and error message, build a trampoline and issue a small
|
||||
jump instruction to it.
|
||||
(x86_install_fast_tracepoint_jump_pad): Add arguments for
|
||||
trampoline and error message.
|
||||
(x86_get_min_fast_tracepoint_insn_len): New.
|
||||
(the_low_target): Add call to x86_get_min_fast_tracepoint_insn_len.
|
||||
* linux-low.h (struct linux_target_ops): Add arguments to
|
||||
install_fast_tracepoint_jump_pad operation, add new operation.
|
||||
* linux-low.c (linux_install_fast_tracepoint_jump_pad): Add
|
||||
arguments.
|
||||
(linux_get_min_fast_tracepoint_insn_len): New function.
|
||||
(linux_target_op): Add new operation.
|
||||
* tracepoint.c (gdb_trampoline_buffer): New IPA variable.
|
||||
(gdb_trampoline_buffer_end): Ditto.
|
||||
(gdb_trampoline_buffer_error): Ditto.
|
||||
(struct ipa_sym_addresses): Add fields for new IPA variables.
|
||||
(symbol_list): Add entries for new IPA variables.
|
||||
(struct tracepoint): Add fields to hold the address range of the
|
||||
trampoline used by the tracepoint.
|
||||
(trampoline_buffer_head): New static variable.
|
||||
(trampoline_buffer_tail): Ditto.
|
||||
(claim_trampoline_space): New function.
|
||||
(have_fast_tracepoint_trampoline_buffer): New function.
|
||||
(clone_fast_tracepoint): Fill in trampoline fields of tracepoint
|
||||
structure.
|
||||
(install_fast_tracepoint): Ditto, also add error buffer argument.
|
||||
(cmd_qtminftpilen): New function.
|
||||
(handle_tracepoint_query): Add response to qTMinFTPILen packet.
|
||||
(fast_tracepoint_from_trampoline_address): New function.
|
||||
(fast_tracepoint_collecting): Handle trampoline as part of jump
|
||||
pad space.
|
||||
(set_trampoline_buffer_space): New function.
|
||||
(initialize_tracepoint): Initialize new IPA variables.
|
||||
* target.h (struct target_ops): Add arguments to
|
||||
install_fast_tracepoint_jump_pad operation, add new
|
||||
get_min_fast_tracepoint_insn_len operation.
|
||||
(target_get_min_fast_tracepoint_insn_len): New.
|
||||
(install_fast_tracepoint_jump_pad): Add arguments.
|
||||
* server.h (IPA_BUFSIZ): Define.
|
||||
* linux-i386-ipa.c: Include extra header files.
|
||||
(initialize_fast_tracepoint_trampoline_buffer): New function.
|
||||
(initialize_low_tracepoint): Call it.
|
||||
* server.h (set_trampoline_buffer_space): Declare.
|
||||
(claim_trampoline_space): Ditto.
|
||||
(have_fast_tracepoint_trampoline_buffer): Ditto.
|
||||
|
||||
2011-11-14 Yao Qi <yao@codesourcery.com>
|
||||
|
||||
* server.c (handle_query): Handle InstallInTrace for qSupported.
|
||||
|
@ -19,6 +19,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "server.h"
|
||||
#include <stdint.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
/* GDB register numbers. */
|
||||
|
||||
@ -191,8 +193,62 @@ supply_static_tracepoint_registers (struct regcache *regcache,
|
||||
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;
|
||||
/* Ensure that the buffer will be at least 1 KiB in size, which is
|
||||
enough space for over 200 fast tracepoints. */
|
||||
const int min_buffer_size = 1024;
|
||||
char buf[IPA_BUFSIZ];
|
||||
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, IPA_BUFSIZ, f))
|
||||
sscanf (buf, "%llu", &mmap_min_addr);
|
||||
|
||||
fclose (f);
|
||||
|
||||
buffer_size = buffer_end - mmap_min_addr;
|
||||
|
||||
if (buffer_size >= min_buffer_size)
|
||||
{
|
||||
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, IPA_BUFSIZ, "low-64K-buffer mmap() failed: %s",
|
||||
strerror (errno));
|
||||
set_trampoline_buffer_space (0, 0, buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf (buf, IPA_BUFSIZ, "mmap_min_addr is %d, must be %d or less",
|
||||
(int) mmap_min_addr, (int) buffer_end - min_buffer_size);
|
||||
set_trampoline_buffer_space (0, 0, buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initialize_low_tracepoint (void)
|
||||
{
|
||||
init_registers_i386_linux ();
|
||||
initialize_fast_tracepoint_trampoline_buffer ();
|
||||
}
|
||||
|
@ -4933,15 +4933,20 @@ linux_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
|
||||
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)
|
||||
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, jjump_pad_insn, jjump_pad_insn_size,
|
||||
adjusted_insn_addr, adjusted_insn_addr_end);
|
||||
jump_entry, trampoline, trampoline_size,
|
||||
jjump_pad_insn, jjump_pad_insn_size,
|
||||
adjusted_insn_addr, adjusted_insn_addr_end,
|
||||
err);
|
||||
}
|
||||
|
||||
static struct emit_ops *
|
||||
@ -4953,6 +4958,12 @@ linux_emit_ops (void)
|
||||
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,
|
||||
@ -5014,6 +5025,7 @@ static struct target_ops linux_target_ops = {
|
||||
linux_install_fast_tracepoint_jump_pad,
|
||||
linux_emit_ops,
|
||||
linux_supports_disable_randomization,
|
||||
linux_get_min_fast_tracepoint_insn_len,
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -132,14 +132,22 @@ struct linux_target_ops
|
||||
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);
|
||||
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;
|
||||
|
@ -42,6 +42,7 @@ void init_registers_amd64_avx_linux (void);
|
||||
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. */
|
||||
|
||||
@ -1182,10 +1183,13 @@ amd64_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
|
||||
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)
|
||||
CORE_ADDR *adjusted_insn_addr_end,
|
||||
char *err)
|
||||
{
|
||||
unsigned char buf[40];
|
||||
int i, offset;
|
||||
@ -1346,10 +1350,13 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
|
||||
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)
|
||||
CORE_ADDR *adjusted_insn_addr_end,
|
||||
char *err)
|
||||
{
|
||||
unsigned char buf[0x100];
|
||||
int i, offset;
|
||||
@ -1455,7 +1462,7 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
|
||||
buf[i++] = 0x0f; /* pop %fs */
|
||||
buf[i++] = 0xa1;
|
||||
buf[i++] = 0x07; /* pop %es */
|
||||
buf[i++] = 0x1f; /* pop %de */
|
||||
buf[i++] = 0x1f; /* pop %ds */
|
||||
buf[i++] = 0x9d; /* popf */
|
||||
buf[i++] = 0x83; /* add $0x4,%esp (pop of tpaddr aka $pc) */
|
||||
buf[i++] = 0xc4;
|
||||
@ -1479,11 +1486,40 @@ i386_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
|
||||
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);
|
||||
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;
|
||||
@ -1497,29 +1533,83 @@ x86_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
|
||||
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)
|
||||
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);
|
||||
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);
|
||||
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 errbuf[IPA_BUFSIZ];
|
||||
|
||||
errbuf[0] = '\0';
|
||||
|
||||
/* 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 (errbuf))
|
||||
return 4;
|
||||
else
|
||||
{
|
||||
/* GDB has no channel to explain to user why a shorter fast
|
||||
tracepoint is not possible, but at least make GDBserver
|
||||
mention that something has gone awry. */
|
||||
if (!warned_about_fast_tracepoints)
|
||||
{
|
||||
warning ("4-byte fast tracepoints not available; %s\n", errbuf);
|
||||
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
|
||||
@ -2873,5 +2963,6 @@ struct linux_target_ops the_low_target =
|
||||
x86_supports_tracepoints,
|
||||
x86_get_thread_area,
|
||||
x86_install_fast_tracepoint_jump_pad,
|
||||
x86_emit_ops
|
||||
x86_emit_ops,
|
||||
x86_get_min_fast_tracepoint_insn_len,
|
||||
};
|
||||
|
@ -429,6 +429,10 @@ char *pfildes (gdb_fildes_t fd);
|
||||
|
||||
/* Functions from tracepoint.c */
|
||||
|
||||
/* Size for a small buffer to report problems from the in-process
|
||||
agent back to GDBserver. */
|
||||
#define IPA_BUFSIZ 100
|
||||
|
||||
int in_process_agent_loaded (void);
|
||||
|
||||
void initialize_tracepoint (void);
|
||||
@ -494,8 +498,13 @@ void supply_fast_tracepoint_registers (struct regcache *regcache,
|
||||
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. */
|
||||
|
@ -359,20 +359,26 @@ struct target_ops
|
||||
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. */
|
||||
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);
|
||||
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. */
|
||||
@ -380,6 +386,10 @@ struct target_ops
|
||||
|
||||
/* 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;
|
||||
@ -437,6 +447,10 @@ void set_target_ops (struct target_ops *);
|
||||
#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)
|
||||
|
||||
@ -471,17 +485,23 @@ void set_target_ops (struct target_ops *);
|
||||
#define install_fast_tracepoint_jump_pad(tpoint, tpaddr, \
|
||||
collector, lockaddr, \
|
||||
orig_size, \
|
||||
jump_entry, jjump_pad_insn, \
|
||||
jump_entry, \
|
||||
trampoline, trampoline_size, \
|
||||
jjump_pad_insn, \
|
||||
jjump_pad_insn_size, \
|
||||
adjusted_insn_addr, \
|
||||
adjusted_insn_addr_end) \
|
||||
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)
|
||||
adjusted_insn_addr_end, \
|
||||
err)
|
||||
|
||||
#define target_emit_ops() \
|
||||
(the_target->emit_ops ? (*the_target->emit_ops) () : NULL)
|
||||
|
@ -110,6 +110,9 @@ trace_vdebug (const char *fmt, ...)
|
||||
# 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
|
||||
@ -148,6 +151,9 @@ struct ipa_sym_addresses
|
||||
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;
|
||||
@ -192,6 +198,9 @@ static struct
|
||||
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),
|
||||
@ -658,6 +667,12 @@ struct tracepoint
|
||||
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;
|
||||
@ -1248,7 +1263,7 @@ static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR);
|
||||
|
||||
static void install_tracepoint (struct tracepoint *, char *own_buf);
|
||||
static void download_tracepoint (struct tracepoint *);
|
||||
static int install_fast_tracepoint (struct tracepoint *);
|
||||
static int install_fast_tracepoint (struct tracepoint *, char *errbuf);
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
@ -2711,6 +2726,85 @@ claim_jump_space (ULONGEST used)
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buf)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
strcpy (buf, "was claiming");
|
||||
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_error,
|
||||
&errbuf))
|
||||
{
|
||||
fatal ("error extracting errbuf");
|
||||
return 0;
|
||||
}
|
||||
|
||||
read_inferior_memory (errbuf, (unsigned char *) buf, 100);
|
||||
}
|
||||
|
||||
return trampoline_end != 0;
|
||||
}
|
||||
|
||||
/* Ask the IPA to probe the marker at ADDRESS. Returns -1 if running
|
||||
the command fails, or 0 otherwise. If the command ran
|
||||
successfully, but probing the marker failed, ERROUT will be filled
|
||||
@ -2743,6 +2837,8 @@ clone_fast_tracepoint (struct tracepoint *to, const struct tracepoint *from)
|
||||
{
|
||||
to->jump_pad = from->jump_pad;
|
||||
to->jump_pad_end = from->jump_pad_end;
|
||||
to->trampoline = from->trampoline;
|
||||
to->trampoline_end = from->trampoline_end;
|
||||
to->adjusted_insn_addr = from->adjusted_insn_addr;
|
||||
to->adjusted_insn_addr_end = from->adjusted_insn_addr_end;
|
||||
to->handle = from->handle;
|
||||
@ -2757,26 +2853,41 @@ clone_fast_tracepoint (struct tracepoint *to, const struct tracepoint *from)
|
||||
non-zero. */
|
||||
|
||||
static int
|
||||
install_fast_tracepoint (struct tracepoint *tpoint)
|
||||
install_fast_tracepoint (struct tracepoint *tpoint, char *errbuf)
|
||||
{
|
||||
CORE_ADDR jentry, jump_entry;
|
||||
CORE_ADDR trampoline;
|
||||
ULONGEST trampoline_size;
|
||||
int err = 0;
|
||||
/* The jump to the jump pad of the last fast tracepoint
|
||||
installed. */
|
||||
unsigned char fjump[MAX_JUMP_SIZE];
|
||||
ULONGEST fjump_size;
|
||||
|
||||
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.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
jentry = jump_entry = get_jump_space_head ();
|
||||
|
||||
trampoline = 0;
|
||||
trampoline_size = 0;
|
||||
|
||||
/* Install the jump pad. */
|
||||
err = install_fast_tracepoint_jump_pad (tpoint->obj_addr_on_target,
|
||||
tpoint->address,
|
||||
ipa_sym_addrs.addr_gdb_collect,
|
||||
ipa_sym_addrs.addr_collecting,
|
||||
tpoint->orig_size,
|
||||
&jentry, fjump, &fjump_size,
|
||||
&jentry,
|
||||
&trampoline, &trampoline_size,
|
||||
fjump, &fjump_size,
|
||||
&tpoint->adjusted_insn_addr,
|
||||
&tpoint->adjusted_insn_addr_end);
|
||||
&tpoint->adjusted_insn_addr_end,
|
||||
errbuf);
|
||||
|
||||
if (err)
|
||||
return 1;
|
||||
@ -2789,6 +2900,8 @@ install_fast_tracepoint (struct tracepoint *tpoint)
|
||||
{
|
||||
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);
|
||||
@ -2849,7 +2962,7 @@ install_tracepoint (struct tracepoint *tpoint, char *own_buf)
|
||||
if (tp) /* TPOINT is installed at the same address as TP. */
|
||||
clone_fast_tracepoint (tpoint, tp);
|
||||
else
|
||||
install_fast_tracepoint (tpoint);
|
||||
install_fast_tracepoint (tpoint, own_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2937,9 +3050,8 @@ cmd_qtstart (char *packet)
|
||||
clone_fast_tracepoint (tpoint, prev_ftpoint);
|
||||
else
|
||||
{
|
||||
if (install_fast_tracepoint (tpoint) == 0)
|
||||
if (install_fast_tracepoint (tpoint, packet) == 0)
|
||||
prev_ftpoint = tpoint;
|
||||
|
||||
}
|
||||
}
|
||||
else if (tpoint->type == static_tracepoint)
|
||||
@ -3514,6 +3626,15 @@ cmd_qtstmat (char *packet)
|
||||
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. */
|
||||
@ -3710,6 +3831,11 @@ handle_tracepoint_query (char *packet)
|
||||
cmd_qtstmat (packet);
|
||||
return 1;
|
||||
}
|
||||
else if (strcmp ("qTMinFTPILen", packet) == 0)
|
||||
{
|
||||
cmd_qtminftpilen (packet);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -5326,6 +5452,23 @@ fast_tracepoint_from_jump_pad_address (CORE_ADDR pc)
|
||||
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. */
|
||||
@ -5388,6 +5531,8 @@ fast_tracepoint_collecting (CORE_ADDR thread_area,
|
||||
{
|
||||
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;
|
||||
|
||||
@ -5426,6 +5571,13 @@ fast_tracepoint_collecting (CORE_ADDR thread_area,
|
||||
&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)
|
||||
{
|
||||
@ -5454,6 +5606,30 @@ fast_tracepoint_collecting (CORE_ADDR thread_area,
|
||||
&& 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;
|
||||
@ -7842,6 +8018,24 @@ gdb_ust_init (void)
|
||||
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);
|
||||
else
|
||||
strcpy (gdb_trampoline_buffer_error, "no buffer passed");
|
||||
}
|
||||
|
||||
static void __attribute__ ((constructor))
|
||||
initialize_tracepoint_ftlib (void)
|
||||
@ -7903,6 +8097,16 @@ initialize_tracepoint: mprotect(%p, %d, PROT_READ|PROT_EXEC) failed with %s",
|
||||
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 when the problem occurs. */
|
||||
gdb_trampoline_buffer_error = xmalloc (IPA_BUFSIZ);
|
||||
|
||||
strcpy (gdb_trampoline_buffer_error, "No errors reported");
|
||||
|
||||
initialize_low_tracepoint ();
|
||||
#endif
|
||||
}
|
||||
|
@ -7109,10 +7109,12 @@ static const int i386_record_regmap[] =
|
||||
};
|
||||
|
||||
/* Check that the given address appears suitable for a fast
|
||||
tracepoint, which on x86 means that we need an instruction of at
|
||||
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. Returns 1 if OK, and writes a size
|
||||
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. */
|
||||
|
||||
@ -7123,10 +7125,26 @@ i386_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
|
||||
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;
|
||||
/* 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)
|
||||
@ -7134,6 +7152,9 @@ i386_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
|
||||
|
||||
/* 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
|
||||
@ -7144,12 +7165,12 @@ i386_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
|
||||
len, jumplen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isize)
|
||||
*isize = len;
|
||||
if (msg)
|
||||
*msg = NULL;
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
if (msg)
|
||||
*msg = NULL;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
|
29
gdb/remote.c
29
gdb/remote.c
@ -6370,7 +6370,7 @@ remote_write_bytes_aux (const char *header, CORE_ADDR memaddr,
|
||||
|
||||
if (todo <= 0)
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("minumum packet size too small to write data"));
|
||||
_("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. */
|
||||
@ -10451,6 +10451,32 @@ remote_traceframe_info (void)
|
||||
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)
|
||||
{
|
||||
@ -10540,6 +10566,7 @@ Specify the serial device it is connected to\n\
|
||||
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;
|
||||
|
@ -689,6 +689,7 @@ update_current_target (void)
|
||||
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);
|
||||
@ -893,6 +894,9 @@ update_current_target (void)
|
||||
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);
|
||||
|
@ -738,6 +738,12 @@ struct target_ops
|
||||
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);
|
||||
@ -1523,6 +1529,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
|
||||
#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)
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2011-11-14 Stan Shebs <stan@codesourcery.com>
|
||||
|
||||
* gdb.trace/ftrace.c: New.
|
||||
* gdb.trace/ftrace.exp: New.
|
||||
|
||||
2011-11-14 Yao Qi <yao@codesourcery.com>
|
||||
|
||||
* gdb.trace/change-loc-1.c: New.
|
||||
|
76
gdb/testsuite/gdb.trace/ftrace.c
Normal file
76
gdb/testsuite/gdb.trace/ftrace.c
Normal file
@ -0,0 +1,76 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2011 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef SYMBOL_PREFIX
|
||||
#define SYMBOL(str) SYMBOL_PREFIX #str
|
||||
#else
|
||||
#define SYMBOL(str) #str
|
||||
#endif
|
||||
|
||||
int globvar;
|
||||
|
||||
static void
|
||||
begin (void)
|
||||
{}
|
||||
|
||||
/* Called from asm. */
|
||||
static void __attribute__((used))
|
||||
func (void)
|
||||
{}
|
||||
|
||||
static void
|
||||
marker (int anarg)
|
||||
{
|
||||
/* `set_point' is the label at which to set a fast tracepoint. The
|
||||
insn at the label must be large enough to fit a fast tracepoint
|
||||
jump. */
|
||||
asm (" .global " SYMBOL(set_point) "\n"
|
||||
SYMBOL(set_point) ":\n"
|
||||
#if (defined __x86_64__ || defined __i386__)
|
||||
" call " SYMBOL(func) "\n"
|
||||
#endif
|
||||
);
|
||||
|
||||
++anarg;
|
||||
|
||||
/* Set up a known 4-byte instruction so we can try to set a shorter
|
||||
fast tracepoint at it. */
|
||||
asm (" .global " SYMBOL(four_byter) "\n"
|
||||
SYMBOL(four_byter) ":\n"
|
||||
#if (defined __i386__)
|
||||
" cmpl $0x1,0x8(%ebp) \n"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
static void
|
||||
end (void)
|
||||
{}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
begin ();
|
||||
|
||||
for (globvar = 1; globvar < 11; ++globvar)
|
||||
{
|
||||
marker (globvar * 100);
|
||||
}
|
||||
|
||||
end ();
|
||||
return 0;
|
||||
}
|
171
gdb/testsuite/gdb.trace/ftrace.exp
Normal file
171
gdb/testsuite/gdb.trace/ftrace.exp
Normal file
@ -0,0 +1,171 @@
|
||||
# Copyright 2011 Free Software Foundation, Inc.
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
load_lib "trace-support.exp";
|
||||
|
||||
set testfile "ftrace"
|
||||
set executable $testfile
|
||||
set srcfile $testfile.c
|
||||
set binfile $objdir/$subdir/$testfile
|
||||
set expfile $testfile.exp
|
||||
|
||||
# Some targets have leading underscores on assembly symbols.
|
||||
set additional_flags [gdb_target_symbol_prefix_flags]
|
||||
|
||||
if [prepare_for_testing $expfile $executable $srcfile \
|
||||
[list debug $additional_flags]] {
|
||||
untested "failed to prepare for trace tests"
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![runto_main] {
|
||||
fail "Can't run to main to check for trace support"
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![gdb_target_supports_trace] {
|
||||
unsupported "target does not support trace"
|
||||
return -1
|
||||
}
|
||||
|
||||
set libipa $objdir/../gdbserver/libinproctrace.so
|
||||
gdb_load_shlibs $libipa
|
||||
|
||||
# Can't use prepare_for_testing, because that splits compiling into
|
||||
# building objects and then linking, and we'd fail with "linker input
|
||||
# file unused because linking not done" when building the object.
|
||||
|
||||
if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
|
||||
executable [list debug $additional_flags shlib=$libipa] ] != "" } {
|
||||
untested "failed to compile ftrace tests"
|
||||
return -1
|
||||
}
|
||||
clean_restart ${executable}
|
||||
|
||||
if ![runto_main] {
|
||||
fail "Can't run to main for ftrace tests"
|
||||
return 0
|
||||
}
|
||||
|
||||
proc run_trace_experiment {} {
|
||||
|
||||
gdb_test "continue" \
|
||||
".*Breakpoint \[0-9\]+, begin .*" \
|
||||
"advance to trace begin"
|
||||
|
||||
gdb_test_no_output "tstart" "start trace experiment"
|
||||
|
||||
gdb_test "continue" \
|
||||
".*Breakpoint \[0-9\]+, end .*" \
|
||||
"advance through tracing"
|
||||
|
||||
gdb_test "tstatus" ".*Trace .*" "check on trace status"
|
||||
|
||||
gdb_test "tstop" "" ""
|
||||
}
|
||||
|
||||
proc test_fast_tracepoints {} {
|
||||
|
||||
set fourgood 0
|
||||
|
||||
gdb_test "break begin" ".*" ""
|
||||
|
||||
gdb_test "break end" ".*" ""
|
||||
|
||||
gdb_test "print gdb_agent_gdb_trampoline_buffer_error" ".*" ""
|
||||
|
||||
if { [is_x86_like_target] } {
|
||||
|
||||
gdb_test "ftrace set_point" "Fast tracepoint .*" \
|
||||
"fast tracepoint at a long insn"
|
||||
|
||||
gdb_trace_setactions "collect at set_point: define actions" \
|
||||
"" \
|
||||
"collect globvar, anarg" "^$"
|
||||
|
||||
# Make a test of shorter fast tracepoints, 32-bit x86 only
|
||||
|
||||
if { [istarget "i?86-*-*"] } {
|
||||
|
||||
# A Linux target needs to be able to allocate trampolines in the
|
||||
# 16-bit range, check mmap_min_addr so we can warn testers.
|
||||
if { [istarget "i?86-*-linux*"] } {
|
||||
|
||||
set minaddr [exec sh -c "cat /proc/sys/vm/mmap_min_addr"]
|
||||
|
||||
if { [expr $minaddr > 64512] } {
|
||||
warning "mmap_min_addr > 64512, fast tracepoint will fail"
|
||||
warning "do \"sudo sysctl -w vm.mmap_min_addr=32768\" to adjust"
|
||||
}
|
||||
}
|
||||
|
||||
gdb_test_multiple "ftrace four_byter" "set 4-byte fast tracepoint" {
|
||||
-re "May not have a fast tracepoint at .*" {
|
||||
pass "4-byte fast tracepoint could not be set"
|
||||
}
|
||||
-re "Fast tracepoint .*" {
|
||||
pass "4-byte fast tracepoint is set"
|
||||
set fourgood 1
|
||||
}
|
||||
}
|
||||
|
||||
if { $fourgood } {
|
||||
|
||||
gdb_trace_setactions "collect at four_byter: define actions" \
|
||||
"" \
|
||||
"collect globvar, anarg" "^$"
|
||||
}
|
||||
}
|
||||
|
||||
run_trace_experiment
|
||||
|
||||
gdb_test "tfind pc *set_point" "Found trace frame .*" \
|
||||
"tfind set_point frame, first time"
|
||||
|
||||
gdb_test "print globvar" " = 1"
|
||||
|
||||
gdb_test "tfind pc *set_point" "Found trace frame .*" \
|
||||
"tfind set_point frame, second time"
|
||||
|
||||
gdb_test "print anarg" " = 200"
|
||||
|
||||
gdb_test "tfind start" "Found trace frame .*" \
|
||||
"reset tfinding"
|
||||
|
||||
if { $fourgood } {
|
||||
|
||||
gdb_test "tfind pc *four_byter" "Found trace frame .*" \
|
||||
"tfind four_byter frame, first time"
|
||||
|
||||
gdb_test "print anarg" " = 101" \
|
||||
"look at collected local, first time"
|
||||
|
||||
gdb_test "tfind pc *four_byter" "Found trace frame .*" \
|
||||
"tfind four_byter frame, second time"
|
||||
|
||||
gdb_test "print anarg" " = 201" \
|
||||
"look at collected local, second time"
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gdb_reinitialize_dir $srcdir/$subdir
|
||||
|
||||
if { [gdb_test "info sharedlibrary" ".*libinproctrace\.so.*" "IPA loaded"] != 0 } {
|
||||
untested "Could not find IPA lib loaded"
|
||||
return 1
|
||||
}
|
||||
|
||||
test_fast_tracepoints
|
Loading…
Reference in New Issue
Block a user