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:
Stan Shebs 2011-11-14 20:07:25 +00:00
parent 3e05895e9e
commit 405f8e9499
19 changed files with 882 additions and 45 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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 ();
}

View File

@ -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

View File

@ -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;

View File

@ -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,
};

View File

@ -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. */

View File

@ -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)

View File

@ -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
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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.

View 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;
}

View 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