aboutsummaryrefslogtreecommitdiff
path: root/gdb/i386-tdep.c
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 /gdb/i386-tdep.c
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.
Diffstat (limited to 'gdb/i386-tdep.c')
-rw-r--r--gdb/i386-tdep.c82
1 files changed, 82 insertions, 0 deletions
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);