2010-05-26  Pedro Alves  <pedro@codesourcery.com>

	* NEWS: Mention the `qRelocInsn' feature.
	* gdbarch.sh (relocate_instruction): New.
	* amd64-tdep.c (rip_relative_offset): New.
	(append_insns): New.
	(amd64_relocate_instruction): New.
	(amd64_init_abi): Install it.
	* i386-tdep.c (append_insns): New.
	(i386_relocate_instruction): New.
	(i386_gdbarch_init): Install it.
	* remote.c (remote_get_noisy_reply): Handle qRelocInsn requests.
	* gdbarch.h, gdbarch.c: Regenerate.

gdb/doc/
2010-05-26  Pedro Alves  <pedro@codesourcery.com>

	* gdb.texinfo (General Query Packets) <qSupported>: Describe the
	`qRelocInsn' feature.
	(Relocate instruction reply packet): New subsection
	of `Tracepoint Packets'.
	(Tracepoint Packets): Mention that packets QTDP and QTStart
	support the qRelocInsn request, and add cross reference to new
	subsection.
This commit is contained in:
Pedro Alves 2010-05-26 18:19:28 +00:00
parent 0a5b531f15
commit dde08ee109
10 changed files with 406 additions and 9 deletions

View File

@ -1,3 +1,17 @@
2010-05-26 Pedro Alves <pedro@codesourcery.com>
* NEWS: Mention the `qRelocInsn' feature.
* gdbarch.sh (relocate_instruction): New.
* amd64-tdep.c (rip_relative_offset): New.
(append_insns): New.
(amd64_relocate_instruction): New.
(amd64_init_abi): Install it.
* i386-tdep.c (append_insns): New.
(i386_relocate_instruction): New.
(i386_gdbarch_init): Install it.
* remote.c (remote_get_noisy_reply): Handle qRelocInsn requests.
* gdbarch.h, gdbarch.c: Regenerate.
2010-05-26 Tom Tromey <tromey@redhat.com>
* dwarf2loc.h (struct dwarf2_locexpr_baton) <data>: Now const.

View File

@ -18,6 +18,15 @@ qGetTIBAddr
Return the address of the Windows Thread Information Block of a given thread.
qRelocInsn
In response to several of the tracepoint packets, the target may now
also respond with a number of intermediate `qRelocInsn' request
packets before the final result packet, to have GDB handle
relocating an instruction to execute at a different address. This
is particularly useful for stubs that support fast tracepoints. GDB
reports support for this feature in the qSupported packet.
* The source command now accepts a -s option to force searching for the
script in the source search path even if the script name specifies
a directory.

View File

@ -1507,6 +1507,123 @@ amd64_displaced_step_fixup (struct gdbarch *gdbarch,
paddress (gdbarch, retaddr));
}
}
/* If the instruction INSN uses RIP-relative addressing, return the
offset into the raw INSN where the displacement to be adjusted is
found. Returns 0 if the instruction doesn't use RIP-relative
addressing. */
static int
rip_relative_offset (struct amd64_insn *insn)
{
if (insn->modrm_offset != -1)
{
gdb_byte modrm = insn->raw_insn[insn->modrm_offset];
if ((modrm & 0xc7) == 0x05)
{
/* The displacement is found right after the ModRM byte. */
return insn->modrm_offset + 1;
}
}
return 0;
}
static void
append_insns (CORE_ADDR *to, ULONGEST len, const gdb_byte *buf)
{
target_write_memory (*to, buf, len);
*to += len;
}
void
amd64_relocate_instruction (struct gdbarch *gdbarch,
CORE_ADDR *to, CORE_ADDR oldloc)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int len = gdbarch_max_insn_length (gdbarch);
/* Extra space for sentinels. */
int fixup_sentinel_space = len;
gdb_byte *buf = xmalloc (len + fixup_sentinel_space);
struct amd64_insn insn_details;
int offset = 0;
LONGEST rel32, newrel;
gdb_byte *insn;
int insn_length;
read_memory (oldloc, buf, len);
/* Set up the sentinel space so we don't have to worry about running
off the end of the buffer. An excessive number of leading prefixes
could otherwise cause this. */
memset (buf + len, 0, fixup_sentinel_space);
insn = buf;
amd64_get_insn_details (insn, &insn_details);
insn_length = gdb_buffered_insn_length (gdbarch, insn, len, oldloc);
/* Skip legacy instruction prefixes. */
insn = amd64_skip_prefixes (insn);
/* Adjust calls with 32-bit relative addresses as push/jump, with
the address pushed being the location where the original call in
the user program would return to. */
if (insn[0] == 0xe8)
{
gdb_byte push_buf[16];
unsigned int ret_addr;
/* Where "ret" in the original code will return to. */
ret_addr = oldloc + insn_length;
push_buf[0] = 0x68; /* pushq $... */
memcpy (&push_buf[1], &ret_addr, 4);
/* Push the push. */
append_insns (to, 5, push_buf);
/* Convert the relative call to a relative jump. */
insn[0] = 0xe9;
/* Adjust the destination offset. */
rel32 = extract_signed_integer (insn + 1, 4, byte_order);
newrel = (oldloc - *to) + rel32;
store_signed_integer (insn + 1, 4, newrel, byte_order);
/* Write the adjusted jump into its displaced location. */
append_insns (to, 5, insn);
return;
}
offset = rip_relative_offset (&insn_details);
if (!offset)
{
/* Adjust jumps with 32-bit relative addresses. Calls are
already handled above. */
if (insn[0] == 0xe9)
offset = 1;
/* Adjust conditional jumps. */
else if (insn[0] == 0x0f && (insn[1] & 0xf0) == 0x80)
offset = 2;
}
if (offset)
{
rel32 = extract_signed_integer (insn + offset, 4, byte_order);
newrel = (oldloc - *to) + rel32;
store_signed_integer (insn + offset, 4, newrel, byte_order);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"Adjusted insn rel32=0x%s at 0x%s to"
" rel32=0x%s at 0x%s\n",
hex_string (rel32), paddress (gdbarch, oldloc),
hex_string (newrel), paddress (gdbarch, *to));
}
/* Write the adjusted instruction into its displaced location. */
append_insns (to, insn_length, buf);
}
/* The maximum number of saved registers. This should include %rip. */
#define AMD64_NUM_SAVED_REGS AMD64_NUM_GREGS
@ -2363,6 +2480,8 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
amd64_regset_from_core_section);
set_gdbarch_get_longjmp_target (gdbarch, amd64_get_longjmp_target);
set_gdbarch_relocate_instruction (gdbarch, amd64_relocate_instruction);
}
/* Provide a prototype to silence -Wmissing-prototypes. */

View File

@ -1,3 +1,13 @@
2010-05-26 Pedro Alves <pedro@codesourcery.com>
* gdb.texinfo (General Query Packets) <qSupported>: Describe the
`qRelocInsn' feature.
(Relocate instruction reply packet): New subsection
of `Tracepoint Packets'.
(Tracepoint Packets): Mention that packets QTDP and QTStart
support the qRelocInsn request, and add cross reference to new
subsection.
2010-05-25 Doug Evans <dje@google.com>
* gdb.texinfo (Exception Handling): Document gdb.GdbError.

View File

@ -31446,6 +31446,11 @@ This feature indicates that @value{GDBN} supports the XML target
description. If the stub sees @samp{xmlRegisters=} with target
specific strings separated by a comma, it will report register
description.
@item qRelocInsn
This feature indicates whether @value{GDBN} supports the
@samp{qRelocInsn} packet (@pxref{Tracepoint Packets,,Relocate
instruction reply packet}).
@end table
Stubs should ignore any unknown values for
@ -32054,6 +32059,8 @@ Replies:
@table @samp
@item OK
The packet was understood and carried out.
@item qRelocInsn
@xref{Tracepoint Packets,,Relocate instruction reply packet}.
@item
The packet was not recognized.
@end table
@ -32118,6 +32125,8 @@ Replies:
@table @samp
@item OK
The packet was understood and carried out.
@item qRelocInsn
@xref{Tracepoint Packets,,Relocate instruction reply packet}.
@item
The packet was not recognized.
@end table
@ -32209,8 +32218,10 @@ Like @samp{QTFrame:range:@var{start}:@var{end}}, but select the first
frame @emph{outside} the given range of addresses (exclusive).
@item QTStart
Begin the tracepoint experiment. Begin collecting data from tracepoint
hits in the trace frame buffer.
Begin the tracepoint experiment. Begin collecting data from
tracepoint hits in the trace frame buffer. This packet supports the
@samp{qRelocInsn} reply (@pxref{Tracepoint Packets,,Relocate
instruction reply packet}).
@item QTStop
End the tracepoint experiment. Stop collecting trace frames.
@ -32371,6 +32382,44 @@ This packet directs the target to use a circular trace buffer if
@end table
@subsection Relocate instruction reply packet
When installing fast tracepoints in memory, the target may need to
relocate the instruction currently at the tracepoint address to a
different address in memory. For most instructions, a simple copy is
enough, but, for example, call instructions that implicitly push the
return address on the stack, and relative branches or other
PC-relative instructions require offset adjustment, so that the effect
of executing the instruction at a different address is the same as if
it had executed in the original location.
In response to several of the tracepoint packets, the target may also
respond with a number of intermediate @samp{qRelocInsn} request
packets before the final result packet, to have @value{GDBN} handle
this relocation operation. If a packet supports this mechanism, its
documentation will explicitly say so. See for example the above
descriptions for the @samp{QTStart} and @samp{QTDP} packets. The
format of the request is:
@table @samp
@item qRelocInsn:@var{from};@var{to}
This requests @value{GDBN} to copy instruction at address @var{from}
to address @var{to}, possibly adjusted so that executing the
instruction at @var{to} has the same effect as executing it at
@var{from}. @value{GDBN} writes the adjusted instruction to target
memory starting at @var{to}.
@end table
Replies:
@table @samp
@item qRelocInsn:@var{adjusted_size}
Informs the stub the relocation is complete. @var{adjusted_size} is
the length in bytes of resulting relocated instruction sequence.
@item E @var{NN}
A badly formed request was detected, or an error was encountered while
relocating the instruction.
@end table
@node Host I/O Packets
@section Host I/O Packets
@cindex Host I/O, remote protocol

View File

@ -245,6 +245,7 @@ struct gdbarch
gdbarch_displaced_step_fixup_ftype *displaced_step_fixup;
gdbarch_displaced_step_free_closure_ftype *displaced_step_free_closure;
gdbarch_displaced_step_location_ftype *displaced_step_location;
gdbarch_relocate_instruction_ftype *relocate_instruction;
gdbarch_overlay_update_ftype *overlay_update;
gdbarch_core_read_description_ftype *core_read_description;
gdbarch_static_transform_name_ftype *static_transform_name;
@ -392,6 +393,7 @@ struct gdbarch startup_gdbarch =
0, /* displaced_step_fixup */
NULL, /* displaced_step_free_closure */
NULL, /* displaced_step_location */
0, /* relocate_instruction */
0, /* overlay_update */
0, /* core_read_description */
0, /* static_transform_name */
@ -493,6 +495,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
gdbarch->displaced_step_fixup = NULL;
gdbarch->displaced_step_free_closure = NULL;
gdbarch->displaced_step_location = NULL;
gdbarch->relocate_instruction = NULL;
gdbarch->target_signal_from_host = default_target_signal_from_host;
gdbarch->target_signal_to_host = default_target_signal_to_host;
gdbarch->has_shared_address_space = default_has_shared_address_space;
@ -667,6 +670,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
fprintf_unfiltered (log, "\n\tdisplaced_step_free_closure");
if ((! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn))
fprintf_unfiltered (log, "\n\tdisplaced_step_location");
/* Skip verify of relocate_instruction, has predicate */
/* Skip verify of overlay_update, has predicate */
/* Skip verify of core_read_description, has predicate */
/* Skip verify of static_transform_name, has predicate */
@ -1104,6 +1108,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: regset_from_core_section = <%s>\n",
host_address_to_string (gdbarch->regset_from_core_section));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_relocate_instruction_p() = %d\n",
gdbarch_relocate_instruction_p (gdbarch));
fprintf_unfiltered (file,
"gdbarch_dump: relocate_instruction = <%s>\n",
host_address_to_string (gdbarch->relocate_instruction));
fprintf_unfiltered (file,
"gdbarch_dump: remote_breakpoint_from_pc = <%s>\n",
host_address_to_string (gdbarch->remote_breakpoint_from_pc));
@ -3302,6 +3312,31 @@ set_gdbarch_displaced_step_location (struct gdbarch *gdbarch,
gdbarch->displaced_step_location = displaced_step_location;
}
int
gdbarch_relocate_instruction_p (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
return gdbarch->relocate_instruction != NULL;
}
void
gdbarch_relocate_instruction (struct gdbarch *gdbarch, CORE_ADDR *to, CORE_ADDR from)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->relocate_instruction != NULL);
/* Do not check predicate: gdbarch->relocate_instruction != NULL, allow call. */
if (gdbarch_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "gdbarch_relocate_instruction called\n");
gdbarch->relocate_instruction (gdbarch, to, from);
}
void
set_gdbarch_relocate_instruction (struct gdbarch *gdbarch,
gdbarch_relocate_instruction_ftype relocate_instruction)
{
gdbarch->relocate_instruction = relocate_instruction;
}
int
gdbarch_overlay_update_p (struct gdbarch *gdbarch)
{

View File

@ -806,6 +806,24 @@ typedef CORE_ADDR (gdbarch_displaced_step_location_ftype) (struct gdbarch *gdbar
extern CORE_ADDR gdbarch_displaced_step_location (struct gdbarch *gdbarch);
extern void set_gdbarch_displaced_step_location (struct gdbarch *gdbarch, gdbarch_displaced_step_location_ftype *displaced_step_location);
/* Relocate an instruction to execute at a different address. OLDLOC
is the address in the inferior memory where the instruction to
relocate is currently at. On input, TO points to the destination
where we want the instruction to be copied (and possibly adjusted)
to. On output, it points to one past the end of the resulting
instruction(s). The effect of executing the instruction at TO shall
be the same as if executing it at FROM. For example, call
instructions that implicitly push the return address on the stack
should be adjusted to return to the instruction after OLDLOC;
relative branches, and other PC-relative instructions need the
offset adjusted; etc. */
extern int gdbarch_relocate_instruction_p (struct gdbarch *gdbarch);
typedef void (gdbarch_relocate_instruction_ftype) (struct gdbarch *gdbarch, CORE_ADDR *to, CORE_ADDR from);
extern void gdbarch_relocate_instruction (struct gdbarch *gdbarch, CORE_ADDR *to, CORE_ADDR from);
extern void set_gdbarch_relocate_instruction (struct gdbarch *gdbarch, gdbarch_relocate_instruction_ftype *relocate_instruction);
/* Refresh overlay mapped state for section OSECT. */
extern int gdbarch_overlay_update_p (struct gdbarch *gdbarch);

View File

@ -708,6 +708,19 @@ m:void:displaced_step_free_closure:struct displaced_step_closure *closure:closur
# see the comments in infrun.c.
m:CORE_ADDR:displaced_step_location:void:::NULL::(! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn)
# Relocate an instruction to execute at a different address. OLDLOC
# is the address in the inferior memory where the instruction to
# relocate is currently at. On input, TO points to the destination
# where we want the instruction to be copied (and possibly adjusted)
# to. On output, it points to one past the end of the resulting
# instruction(s). The effect of executing the instruction at TO shall
# be the same as if executing it at FROM. For example, call
# instructions that implicitly push the return address on the stack
# should be adjusted to return to the instruction after OLDLOC;
# relative branches, and other PC-relative instructions need the
# offset adjusted; etc.
M:void:relocate_instruction:CORE_ADDR *to, CORE_ADDR from:to, from::NULL
# Refresh overlay mapped state for section OSECT.
F:void:overlay_update:struct obj_section *osect:osect

View File

@ -658,6 +658,86 @@ i386_displaced_step_fixup (struct gdbarch *gdbarch,
paddress (gdbarch, retaddr));
}
}
static void
append_insns (CORE_ADDR *to, ULONGEST len, const gdb_byte *buf)
{
target_write_memory (*to, buf, len);
*to += len;
}
static void
i386_relocate_instruction (struct gdbarch *gdbarch,
CORE_ADDR *to, CORE_ADDR oldloc)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
gdb_byte buf[I386_MAX_INSN_LEN];
int offset = 0, rel32, newrel;
int insn_length;
gdb_byte *insn = buf;
read_memory (oldloc, buf, I386_MAX_INSN_LEN);
insn_length = gdb_buffered_insn_length (gdbarch, insn,
I386_MAX_INSN_LEN, oldloc);
/* Get past the prefixes. */
insn = i386_skip_prefixes (insn, I386_MAX_INSN_LEN);
/* Adjust calls with 32-bit relative addresses as push/jump, with
the address pushed being the location where the original call in
the user program would return to. */
if (insn[0] == 0xe8)
{
gdb_byte push_buf[16];
unsigned int ret_addr;
/* Where "ret" in the original code will return to. */
ret_addr = oldloc + insn_length;
push_buf[0] = 0x68; /* pushq $... */
memcpy (&push_buf[1], &ret_addr, 4);
/* Push the push. */
append_insns (to, 5, push_buf);
/* Convert the relative call to a relative jump. */
insn[0] = 0xe9;
/* Adjust the destination offset. */
rel32 = extract_signed_integer (insn + 1, 4, byte_order);
newrel = (oldloc - *to) + rel32;
store_signed_integer (insn + 1, 4, newrel, byte_order);
/* Write the adjusted jump into its displaced location. */
append_insns (to, 5, insn);
return;
}
/* Adjust jumps with 32-bit relative addresses. Calls are already
handled above. */
if (insn[0] == 0xe9)
offset = 1;
/* Adjust conditional jumps. */
else if (insn[0] == 0x0f && (insn[1] & 0xf0) == 0x80)
offset = 2;
if (offset)
{
rel32 = extract_signed_integer (insn + offset, 4, byte_order);
newrel = (oldloc - *to) + rel32;
store_signed_integer (insn + offset, 4, newrel, byte_order);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"Adjusted insn rel32=0x%s at 0x%s to"
" rel32=0x%s at 0x%s\n",
hex_string (rel32), paddress (gdbarch, oldloc),
hex_string (newrel), paddress (gdbarch, *to));
}
/* Write the adjusted instructions into their displaced
location. */
append_insns (to, insn_length, buf);
}
#ifdef I386_REGNO_TO_SYMMETRY
#error "The Sequent Symmetry is no longer supported."
@ -6909,6 +6989,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdesc_data = tdesc_data_alloc ();
set_gdbarch_relocate_instruction (gdbarch, i386_relocate_instruction);
/* Hook in ABI-specific overrides, if they have been registered. */
info.tdep_info = (void *) tdesc_data;
gdbarch_init_osabi (info, gdbarch);

View File

@ -242,6 +242,8 @@ static void remote_terminal_ours (void);
static int remote_read_description_p (struct target_ops *target);
char *unpack_varlen_hex (char *buff, ULONGEST *result);
/* The non-stop remote protocol provisions for one pending stop reply.
This is where we keep it until it is acknowledged. */
@ -433,6 +435,55 @@ remote_get_noisy_reply (char **buf_p,
buf = *buf_p;
if (buf[0] == 'E')
trace_error (buf);
else if (strncmp (buf, "qRelocInsn:", strlen ("qRelocInsn:")) == 0)
{
ULONGEST ul;
CORE_ADDR from, to, org_to;
char *p, *pp;
int adjusted_size = 0;
volatile struct gdb_exception ex;
p = buf + strlen ("qRelocInsn:");
pp = unpack_varlen_hex (p, &ul);
if (*pp != ';')
error (_("invalid qRelocInsn packet: %s\n"), buf);
from = ul;
p = pp + 1;
pp = unpack_varlen_hex (p, &ul);
to = ul;
org_to = to;
TRY_CATCH (ex, RETURN_MASK_ALL)
{
gdbarch_relocate_instruction (target_gdbarch, &to, from);
}
if (ex.reason >= 0)
{
adjusted_size = to - org_to;
sprintf (buf, "qRelocInsn:%x", adjusted_size);
putpkt (buf);
}
else if (ex.reason < 0 && ex.error == MEMORY_ERROR)
{
/* Propagate memory errors silently back to the target.
The stub may have limited the range of addresses we
can write to, for example. */
putpkt ("E01");
}
else
{
/* Something unexpectedly bad happened. Be verbose so
we can tell what, and propagate the error back to the
stub, so it doesn't get stuck waiting for a
response. */
exception_fprintf (gdb_stderr, ex,
_("warning: relocating instruction: "));
putpkt ("E01");
}
}
else if (buf[0] == 'O' && buf[1] != 'K')
remote_console_output (buf + 1); /* 'O' message from stub */
else
@ -3584,13 +3635,10 @@ remote_query_supported (void)
if (remote_support_xml)
q = remote_query_supported_append (q, remote_support_xml);
if (q)
{
q = reconcat (q, "qSupported:", q, (char *) NULL);
putpkt (q);
}
else
putpkt ("qSupported");
q = remote_query_supported_append (q, "qRelocInsn+");
q = reconcat (q, "qSupported:", q, (char *) NULL);
putpkt (q);
do_cleanups (old_chain);