aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2010-05-26 18:19:28 +0000
committerPedro Alves <palves@redhat.com>2010-05-26 18:19:28 +0000
commitdde08ee10924b57d4e1c80e40a6a1fe14c93dcb5 (patch)
tree1d24a9d5f315737edcb115c43f6ae024437126ba
parent0a5b531f15567f9b4d5b5ac6b6e89ee5e8e0e7f0 (diff)
downloadgdb-dde08ee10924b57d4e1c80e40a6a1fe14c93dcb5.zip
gdb-dde08ee10924b57d4e1c80e40a6a1fe14c93dcb5.tar.gz
gdb-dde08ee10924b57d4e1c80e40a6a1fe14c93dcb5.tar.bz2
gdb/
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.
-rw-r--r--gdb/ChangeLog14
-rw-r--r--gdb/NEWS9
-rw-r--r--gdb/amd64-tdep.c119
-rw-r--r--gdb/doc/ChangeLog10
-rw-r--r--gdb/doc/gdb.texinfo53
-rw-r--r--gdb/gdbarch.c35
-rw-r--r--gdb/gdbarch.h18
-rwxr-xr-xgdb/gdbarch.sh13
-rw-r--r--gdb/i386-tdep.c82
-rw-r--r--gdb/remote.c62
10 files changed, 406 insertions, 9 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 46dc0b0..a878f01 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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.
diff --git a/gdb/NEWS b/gdb/NEWS
index f91fe2e..7f41808 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -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.
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 6336b7a..9feed90 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -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. */
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 2124414..d5b7f1c 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -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.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9466745..72c86e9 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 626a9db..bf41ab3 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -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 */
@@ -1105,6 +1109,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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));
fprintf_unfiltered (file,
@@ -3303,6 +3313,31 @@ set_gdbarch_displaced_step_location (struct gdbarch *gdbarch,
}
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)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index af060df..e0c933c 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -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);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 8220788..1e9a489 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -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
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 67cdee4..5e366ea 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -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);
diff --git a/gdb/remote.c b/gdb/remote.c
index 9dc4d2d..16e577b 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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);