Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Doug Evans <dje@google.com>
To: Pedro Alves <pedro@codesourcery.com>
Cc: gdb-patches@sourceware.org
Subject: Re: [RFA] amd64 displaced stepping support
Date: Wed, 28 Jan 2009 12:39:00 -0000	[thread overview]
Message-ID: <e394668d0901280039s4fc7e2ch460040bd09127770@mail.gmail.com> (raw)
In-Reply-To: <200901271715.49852.pedro@codesourcery.com>

[-- Attachment #1: Type: text/plain, Size: 15945 bytes --]

On Tue, Jan 27, 2009 at 9:15 AM, Pedro Alves <pedro@codesourcery.com> wrote:
> On Monday 26 January 2009 23:00:12, Doug Evans wrote:
>> Hi.  I took a crack at implementing displaced stepping support for amd64.
>
> Great!  Thank you so much for this.
>
>> I think the GNU tools need a general-purpose library of ISA-related tools.
>
> Right, opcodes <-> gdb could cooperate better, in several ways.
>
>> Until then, I went with the disassembler.  The code is laid out such that
>> when a better implementation of computing insn lengths comes along, it
>> can be easily dropped in.
>
> Err, well, did you consider adding the needed interfaces to libopcodes?
> It's what we use to implement the disassembler anyway...

I'd like to add the needed interfaces.  I'm just not sure how long a
process that will be and I'd like to get started on exercising amd64
non-stop functionality.  I'll pursue exporting the modrm_bytes arrays
and insn-length computation with binutils.

>
>>       (rex_prefix_p,amd64_insn_length_fprintf,amd64_insn_length_init_dis,
>>       amd64_insn_length,amd64_get_unused_input_int_reg,fixup_riprel,
>
> On the nitpicking department, the standard tells us to split these lines
> as:
>
>        (rex_prefix_p,amd64_insn_length_fprintf,amd64_insn_length_init_dis)
>        (amd64_insn_length,amd64_get_unused_input_int_reg,fixup_riprel)
>        (foo): Base.
>
> Emacs loves this form better too.
>
>>       amd64_displaced_step_fixup): New fns.
>
> Are you really that lazy? :-)  Please spell out "fns", and avoid everyone
> else the extra cycles to expand that.

ok.

>
>> +/* ??? *_has_modrm are copies of the tables in ../opcodes/i386-dis.c.
>> +   It might be nice if we could use them.
>> +   ??? This differs from the kernel version, is one of them out of date?  */
>
> Yes, looks like it.  It is safe to assume that the opcodes version is more
> up to date, as it gets updated to reflect new cpus frequently, by the Intel
> and AMD folks, at least.

I assumed so, but didn't actually know.

> In any case, comments like this are no good, as they're doomed to get out of
> date at some point themselves too.  Better say, "please keep this in
> sync with ... foo".  If not addressing this duplication yourself, please
> do open a PR about it.  This will surelly end up out of date at
> some point...

I've modified the comment to be a warning.

>> +/* Return the length in bytes of INSN.
>> +   MAX_LEN is the size of the buffer containing INSN
>> +   ??? The GNU tools need a library of basic ISA-related support.
>> +   Until then we use the disassembler.       */
>
> ... Why not say something like "Unfortunately, libopcodes doesn't export
> a simpler way to query the length of instruction at a given address.  We
> use the disassembler interface to do that." ...

The attached patch has a different wording.

>> +static int
>> +amd64_insn_length (const gdb_byte *insn, int max_len, CORE_ADDR addr)
>> +{
>> +  struct disassemble_info di;
>> +  struct gdbarch *gdbarch = current_gdbarch;
>
> Ouch, CURRENT_GDBARCH red alert.  From what I can tell, you have a gdbarch
> available to use.  amd64_displaced_step_copy_insn gets a gdbarch* passed in
> as parameter, so you can pass it to fixup_displaced_copy, and then
> to fixup_riprel, which then can pass it here.  Can you do that please?

righto.

>> +/* Return an integer register (other than RSP) that is unused as an input
>> +   operand in INSN.
>> +   MAX_LEN is the size of the buffer containing INSN.
>> +   OPCODE_OFFSET is the offset of the first opcode byte.
>> +   OPCODE_LEN is the number of opcode bytes.
>> +   MODRM_OFFSET is the offset of the ModRM byte or -1 if not present.
>> +   In order to not require adding a rex prefix if the insn doesn't already
>> +   have one, the result is restricted to RAX ... RDI, sans RSP.
>> +   The register numbering of the result follows architecture ordering,
>> +   e.g. RDI = 7.
>> +
>> +   ??? The GNU tools need a library of basic ISA-related support.  */
>
>
>> +    /* We shouldn't get here.  */
>> +    gdb_assert (0);
>
> Use internal_error instead, please.

Ah, righto.

>> +static void
>> +fixup_riprel (struct displaced_step_closure *dsc, CORE_ADDR from, CORE_ADDR to,
>> +           struct regcache *regs)
>> +{
>> +  int modrm_offset = dsc->modrm_offset;
>> +  gdb_byte *insn = dsc->insn_buf + modrm_offset;
>> +  CORE_ADDR rip_base;
>> +  int32_t disp;
>> +  int insn_length;
>> +  int arch_tmp_regno, tmp_regno;
>> +  ULONGEST orig_value;
>> +
>> +  /* %rip+disp32 addressing mode, displacement follows ModRM byte.  */
>> +  ++insn;
>> +
>
>> +  /* Compute the rip-relative address.       */
>> +  disp = *(int32_t*) insn; // FIXME: target-fetch-value
>
> Err, that will cause unaligned traps on some hosts (this is a tdep file, not
> a nat file).  Please fix that up.

Ya, oops.  That one I intended to fix but forgot about.  Fixed.

>> +  insn_length = amd64_insn_length (dsc->insn_buf, dsc->max_len, from);
>> +  rip_base = from + insn_length;
>> +
>> +  /* We need a register to hold the address.
>> +     Pick one not used in the insn.
>> +     NOTE: arch_tmp_regno uses architecture ordering, e.g. RDI = 7.  */
>> +  arch_tmp_regno = amd64_get_unused_input_int_reg (dsc->insn_buf, dsc->max_len,
>> +                                                dsc->opcode_offset,
>> +                                                dsc->opcode_len,
>> +                                                dsc->modrm_offset);
>> +  tmp_regno = amd64_arch_reg_to_regnum (arch_tmp_regno);
>> +
>> +  /* REX.B should be unset as we were using rip-relative addressing,
>> +     but ensure it's unset anyway, tmp_regno is not r8-r15.  */
>> +  if (dsc->rex_offset != -1)
>> +    dsc->insn_buf[dsc->rex_offset] &= ~1;
>> +
>> +  regcache_cooked_read_unsigned (regs, tmp_regno, &orig_value);
>> +  dsc->tmp_regno = tmp_regno;
>> +  dsc->tmp_save = orig_value;
>> +  dsc->tmp_used = 1;
>> +
>> +  /* Convert the ModRM field to be base+disp.  */
>> +  dsc->insn_buf[modrm_offset] &= ~0xc7;
>> +  dsc->insn_buf[modrm_offset] |= 0x80 + arch_tmp_regno;
>> +
>> +  regcache_cooked_write_unsigned (regs, tmp_regno, rip_base);
>> +
>> +  if (debug_displaced)
>> +    fprintf_unfiltered (gdb_stdlog, "displaced: %%rip-relative addressing used.\n"
>> +                     "displaced: using temp reg %d, old value 0x%s, new value 0x%s\n",
>> +                     dsc->tmp_regno, paddr_nz (dsc->tmp_save),
>> +                     paddr_nz (rip_base));
>> +}
>> +
>> +static void
>> +fixup_displaced_copy (struct displaced_step_closure *dsc,
>> +                   CORE_ADDR from, CORE_ADDR to, struct regcache *regs)
>> +{
>> +  gdb_byte *insn = dsc->insn_buf;
>> +  int len = dsc->max_len;
>> +  gdb_byte *start = insn;
>> +  gdb_byte *end = insn + len;
>> +  int need_modrm;
>> +
>> +  /* Skip legacy instruction prefixes.
>> +     While the kernel's kprobes support can assume the instruction is valid,
>> +     we can't.       Don't crash if we see an invalid insn.  */
>
> Yeah, we'd better warn/error out to the user than to do something silly
> with instructions we don't know what to do with.  Should we be checking
> if you've reached >= end somewhere?

The code allocates sufficient extra space to obviate having to
continually test "are we at the end yet?".
A lot of this is copied from i386-tdep.c.  If this patch is ok, I'll
send patches for i386-tdep.c.

>
>> +
>> +  while (insn < end)
>> +    {
>> +      switch (*insn)
>> +     {
>> +     case 0x66:
>> +     case 0x67:
>> +     case 0x2e:
>> +     case 0x3e:
>> +     case 0x26:
>> +     case 0x64:
>> +     case 0x65:
>> +     case 0x36:
>> +     case 0xf0:
>> +     case 0xf3:
>> +     case 0xf2:
>> +       ++insn;
>> +       continue;
>> +     }
>> +      break;
>> +    }
>> +
>> +  /* Skip REX instruction prefix.  */
>> +  if (rex_prefix_p (*insn))
>> +    {
>> +      dsc->rex_offset = insn - start;
>> +      ++insn;
>> +    }
>> +
>> +  dsc->opcode_offset = insn - start;
>> +
>> +  if (*insn == 0x0f)
>> +    {
>> +      /* Two or three-byte opcode.  */
>> +      ++insn;
>> +      need_modrm = twobyte_has_modrm[*insn];
>> +
>> +      /* Check for three-byte opcode.  */
>> +      if (*insn == 0x38 || *insn == 0x3a)
>> +     {
>> +       ++insn;
>> +       dsc->opcode_len = 3;
>> +     }
>> +      else
>> +     dsc->opcode_len = 2;
>> +    }
>> +  else
>> +    {
>> +      /* One-byte opcode.  */
>> +      need_modrm = onebyte_has_modrm[*insn];
>> +      dsc->opcode_len = 1;
>> +    }
>> +
>> +  if (need_modrm)
>> +    {
>> +      gdb_byte modrm = *++insn;
>> +
>> +      dsc->modrm_offset = insn - start;
>> +
>> +      if ((modrm & 0xc7) == 0x05)
>> +     {
>> +       /* The insn uses rip-relative addressing.
>> +          Deal with it.  */
>> +       fixup_riprel (dsc, from, to, regs);
>> +     }
>> +    }
>> +}
>> +
>
>
>> +  /* GDB may get control back after the insn after the syscall.
>> +     If this is a syscall, make sure there's a nop afterwards.  */
>> +  {
>> +    int syscall_length;
>>
>> +    if (amd64_syscall_p (buf, &syscall_length))
>> +      buf[syscall_length] = 0x90;
>> +  }
>
> Weird.  Isn't this a kernel bug?  It only happens when single-stepping
> the syscall insn.  E.g., from your testcase, without displaced stepping:
>
>  58  test_syscall:
>  59     syscall
>  60     nop
>  61  test_syscall_end:
>  62     nop
>
>  (gdb) b amd64-disp-step.S:60
>  Breakpoint 1 at 0x4004fa: file ../../../src/gdb/testsuite/gdb.arch/amd64-disp-step.S, line 60.
>  (gdb) r
>  Starting program: /home/pedro/gdb/baseline/build/gdb/testsuite/gdb.arch/amd64-disp-step
>
>  Breakpoint 1, test_syscall () at ../../../src/gdb/testsuite/gdb.arch/amd64-disp-step.S:60
>  60              nop
>  Current language:  auto; currently asm
>
> But:
>
>  (gdb) c
>  Continuing.
>
>  Program exited normally.
>  (gdb) b 59
>  Breakpoint 2 at 0x4004f8: file ../../../src/gdb/testsuite/gdb.arch/amd64-disp-step.S, line 59.
>  (gdb) r
>  Starting program: /home/pedro/gdb/baseline/build/gdb/testsuite/gdb.arch/amd64-disp-step
>
>  Breakpoint 2, test_syscall () at ../../../src/gdb/testsuite/gdb.arch/amd64-disp-step.S:59
>  59              syscall
>  (gdb) c
>  Continuing.
>
>  Program exited normally.
>  (gdb)
>
> GDB did a single-step to get over the "syscall", and missed the breakpoint
> at 0x4004fa.
>
> Again, doing a manual stepi:
>
>  (gdb) r
>  Starting program: /home/pedro/gdb/baseline/build/gdb/testsuite/gdb.arch/amd64-disp-step
>
>  Breakpoint 2, test_syscall () at ../../../src/gdb/testsuite/gdb.arch/amd64-disp-step.S:59
>  59              syscall
>  (gdb) del 2
>  (gdb) set debug infrun 1
>  (gdb) stepi
>  infrun: clear_proceed_status_thread (process 4322)
>  infrun: proceed (addr=0xffffffffffffffff, signal=144, step=1)
>  During symbol reading, incomplete CFI data; unspecified registers (e.g., rax) at 0x7ffff781b0f3.
>  infrun: resume (step=1, signal=0), trap_expected=0
>  infrun: wait_for_inferior (treat_exec_as_sigtrap=0)
>  infrun: infwait_normal_state
>  infrun: TARGET_WAITKIND_STOPPED
>  infrun: stop_pc = 0x4004fb
>  infrun: stepi/nexti
>  infrun: stop_stepping
>  test_syscall_end () at ../../../src/gdb/testsuite/gdb.arch/amd64-disp-step.S:62
>  62              nop
>  (gdb) stepi
>  test_syscall_end () at ../../../src/gdb/testsuite/gdb.arch/amd64-disp-step.S:62
>  62              nop
>  (gdb) p $pc
>  $1 = (void (*)()) 0x4004fb <test_syscall_end>
>  (gdb)
>
> If you replace the nop with something wider, e.g., try stepping over
> this:
>
>        mov $0x27,%eax /* getpid */
>        syscall
>        mov $0xff,%eax
>        nop
>
> You'll see that the move after the syscall is completely
> stepped over, and that is was executed correctly.

Ya, this is what I discovered during my experiments to understand this.

> Something in the kernel not restoring the trace flag correctly, and
> hence stepping one instruction too much?

Presumably.

>
>> +/* ??? Do we need to check for rex prefix in these predicates, or their
>> +   callers?  */
>
> The caller should (amd64_displaced_step_fixup), I believe?  IIUC, you also
> store the prefixes in dsc->insn_buf.

Well, that comment refers to the insn predicates like amd64_call_p.
Having the caller skip the prefixes muddies their interface.  The
appended patch does something cleaner.

>
>> +
>> +static int
>> +amd64_absolute_jmp_p (gdb_byte *insn)
>> +{
>> +  /* jmp far (absolute address in operand) */
>> +  /* ??? undefined insn actually */
>> +  if (insn[0] == 0xea)
>> +    return 1;
>
> Indeed, invalid in 64-bit mode.  Any reason not to drop it?

Dropped.

>
>> +
>> +  if (insn[0] == 0xff)
>> +    {
>> +      /* jump near, absolute indirect (/4) */
>> +      if ((insn[1] & 0x38) == 0x20)
>> +     return 1;
>> +
>> +      /* jump far, absolute indirect (/5) */
>> +      if ((insn[1] & 0x38) == 0x28)
>> +     return 1;
>> +    }
>> +
>> +  return 0;
>> +}
>> +
>> +static int
>> +amd64_absolute_call_p (gdb_byte *insn)
>> +{
>> +  /* call far, absolute */
>> +  /* ??? undefined insn actually */
>> +  if (insn[0] == 0x9a)
>> +    return 1;
>> +
>
> Same as above.

Righto.

>
>> +  if (insn[0] == 0xff)
>> +    {
>> +      /* Call near, absolute indirect (/2) */
>> +      if ((insn[1] & 0x38) == 0x10)
>> +     return 1;
>> +
>> +      /* Call far, absolute indirect (/3) */
>> +      if ((insn[1] & 0x38) == 0x18)
>> +     return 1;
>> +    }
>> +
>> +  return 0;
>> +}
>> +
>
>> Index: testsuite/gdb.arch/amd64-disp-step.S
>> ===================================================================
>> RCS file: testsuite/gdb.arch/amd64-disp-step.S
>> diff -N testsuite/gdb.arch/amd64-disp-step.S
>
>> +   Please email any bugs, comments, and/or additions to this file to:
>> +   bug-gdb@gnu.org
>
> Hmmm, shoudn't we be stopping using this address?

cut-n-paste.  Deleted.

>
>> +gdb_test "set non-stop on" ""
>> +gdb_test "show non-stop" "Controlling the inferior in non-stop mode is on.*"
>
> Please use "set displaced-stepping on" instead.

Righto.

>
>> +# Done, run program to exit.
>> +
>> +gdb_test "continue" \
>> +    ".*Program exited normally.*" \
>> +    "continue to exit"
>>
>
> Use gdb_continue_to_end instead.

Righto.

Ok to check in?
[Modulo I need to clear the opcode/i386.h additions with binutils.
I'm not sure who to get approval from first.]

2009-01-27  Doug Evans  <dje@google.com>

        * opcode/i386.h: Add multiple inclusion protection.
        (EAX_REG_NUM,ECX_REG_NUM,EDX_REGNUM,EBX_REG_NUM,ESI_REG_NUM)
        (EDI_REG_NUM): New macros.
        (MODRM_MOD_FIELD,MODRM_REG_FIELD,MODRM_RM_FIELD): New macros.
        (SIB_SCALE_FIELD,SIB_INDEX_FIELD,SIB_BASE_FIELD): New macros.
        (REG_PREFIX_P): New macro.

        * amd64-tdep.h (amd64_displaced_step_copy_insn): Declare.
        (amd64_displaced_step_fixup): Declare.
        * amd64-tdep.c: #include opcode/i386.h, dis-asm.h.
        (amd64_arch_regmap): Move out of amd64_analyze_stack_align
        and make static global.
        (amd64_arch_regmap_len): New static global.
        (amd64_arch_reg_to_regnum): New function.
        (struct amd64_insn): New struct.
        (struct displaced_step_closure): New struct.
        (onebyte_has_modrm,twobyte_has_modrm): New static globals.
        (rex_prefix_p,skip_prefixes)
        (amd64_insn_length_fprintf,amd64_insn_length_init_dis)
        (amd64_insn_length,amd64_get_unused_input_int_reg)
        (amd64_get_insn_details,fixup_riprel,fixup_displaced_copy)
        (amd64_displaced_step_copy_insn)
        (amd64_absolute_jmp_p,amd64_absolute_call_p,amd64_ret_p)
        (amd64_call_p,amd64_breakpoint_p,amd64_syscall_p)
        (amd64_displaced_step_fixup): New functions.
        * amd64-linux-tdep.c: #include arch-utils.h.
        (amd64_linux_init_abi): Install displaced stepping support.

        * gdb.arch/amd64-disp-step.S: New file.
        * gdb.arch/amd64-disp-step.exp: New file.
        * gdb.arch/i386-disp-step.S: New file.
        * gdb.arch/i386-disp-step.exp: New file.

[-- Attachment #2: gdb-090128-amd64-disp-step-2.patch.txt --]
[-- Type: text/plain, Size: 44135 bytes --]

2009-01-27  Doug Evans  <dje@google.com>

	* opcode/i386.h: Add multiple inclusion protection.
	(EAX_REG_NUM,ECX_REG_NUM,EDX_REGNUM,EBX_REG_NUM,ESI_REG_NUM)
	(EDI_REG_NUM): New macros.
	(MODRM_MOD_FIELD,MODRM_REG_FIELD,MODRM_RM_FIELD): New macros.
	(SIB_SCALE_FIELD,SIB_INDEX_FIELD,SIB_BASE_FIELD): New macros.
	(REG_PREFIX_P): New macro.

	* amd64-tdep.h (amd64_displaced_step_copy_insn): Declare.
	(amd64_displaced_step_fixup): Declare.
	* amd64-tdep.c: #include opcode/i386.h, dis-asm.h.
	(amd64_arch_regmap): Move out of amd64_analyze_stack_align
	and make static global.
	(amd64_arch_regmap_len): New static global.
	(amd64_arch_reg_to_regnum): New function.
	(struct amd64_insn): New struct.
	(struct displaced_step_closure): New struct.
	(onebyte_has_modrm,twobyte_has_modrm): New static globals.
	(rex_prefix_p,skip_prefixes)
	(amd64_insn_length_fprintf,amd64_insn_length_init_dis)
	(amd64_insn_length,amd64_get_unused_input_int_reg)
	(amd64_get_insn_details,fixup_riprel,fixup_displaced_copy)
	(amd64_displaced_step_copy_insn)
	(amd64_absolute_jmp_p,amd64_absolute_call_p,amd64_ret_p)
	(amd64_call_p,amd64_breakpoint_p,amd64_syscall_p)
	(amd64_displaced_step_fixup): New functions.
	* amd64-linux-tdep.c: #include arch-utils.h.
	(amd64_linux_init_abi): Install displaced stepping support.

	* gdb.arch/amd64-disp-step.S: New file.
	* gdb.arch/amd64-disp-step.exp: New file.
	* gdb.arch/i386-disp-step.S: New file.
	* gdb.arch/i386-disp-step.exp: New file.

Index: include/opcode/i386.h
===================================================================
RCS file: /cvs/src/src/include/opcode/i386.h,v
retrieving revision 1.79
diff -u -p -u -p -r1.79 i386.h
--- include/opcode/i386.h	3 Apr 2008 14:03:20 -0000	1.79
+++ include/opcode/i386.h	28 Jan 2009 08:31:34 -0000
@@ -35,6 +35,9 @@
 
    The affected opcode map is dceX, dcfX, deeX, defX.  */
 
+#ifndef OPCODE_I386_H
+#define OPCODE_I386_H
+
 #ifndef SYSV386_COMPAT
 /* Set non-zero for broken, compatible instructions.  Set to zero for
    non-broken opcodes at your peril.  gcc generates SystemV/386
@@ -72,8 +75,14 @@
 #define NOP_OPCODE (char) 0x90
 
 /* register numbers */
-#define EBP_REG_NUM 5
+#define EAX_REG_NUM 0
+#define ECX_REG_NUM 1
+#define EDX_REG_NUM 2
+#define EBX_REG_NUM 3
 #define ESP_REG_NUM 4
+#define EBP_REG_NUM 5
+#define ESI_REG_NUM 6
+#define EDI_REG_NUM 7
 
 /* modrm_byte.regmem for twobyte escape */
 #define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM
@@ -87,9 +96,22 @@
 #define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */
 #define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG)
 
+/* Extract fields from the mod/rm byte.  */
+#define MODRM_MOD_FIELD(modrm) (((modrm) >> 6) & 3)
+#define MODRM_REG_FIELD(modrm) (((modrm) >> 3) & 7)
+#define MODRM_RM_FIELD(modrm)  (((modrm) >> 0) & 7)
+
+/* Extract fields from the sib byte.  */
+#define SIB_SCALE_FIELD(sib) (((sib) >> 6) & 3)
+#define SIB_INDEX_FIELD(sib) (((sib) >> 3) & 7)
+#define SIB_BASE_FIELD(sib)  (((sib) >> 0) & 7)
+
 /* x86-64 extension prefix.  */
 #define REX_OPCODE	0x40
 
+/* Non-zero if OPCODE is the rex prefix.  */
+#define REX_PREFIX_P(opcode) (((opcode) & 0xf0) == REX_OPCODE)
+
 /* Indicates 64 bit operand size.  */
 #define REX_W	8
 /* High extension to reg field of modrm byte.  */
@@ -113,3 +135,5 @@
 
 /* max size of register name in insn mnemonics.  */
 #define MAX_REG_NAME_SIZE 8
+
+#endif /* OPCODE_I386_H */
Index: gdb/amd64-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/amd64-linux-tdep.c,v
retrieving revision 1.21
diff -u -p -u -p -r1.21 amd64-linux-tdep.c
--- gdb/amd64-linux-tdep.c	3 Jan 2009 05:57:50 -0000	1.21
+++ gdb/amd64-linux-tdep.c	28 Jan 2009 08:31:34 -0000
@@ -20,6 +20,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "arch-utils.h"
 #include "frame.h"
 #include "gdbcore.h"
 #include "regcache.h"
@@ -286,6 +287,15 @@ amd64_linux_init_abi (struct gdbarch_inf
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
                                              svr4_fetch_objfile_link_map);
+
+  /* Displaced stepping.  */
+  set_gdbarch_displaced_step_copy_insn (gdbarch,
+                                        amd64_displaced_step_copy_insn);
+  set_gdbarch_displaced_step_fixup (gdbarch, amd64_displaced_step_fixup);
+  set_gdbarch_displaced_step_free_closure (gdbarch,
+                                           simple_displaced_step_free_closure);
+  set_gdbarch_displaced_step_location (gdbarch,
+                                       displaced_step_at_entry_point);
 }
 \f
 
Index: gdb/amd64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/amd64-tdep.c,v
retrieving revision 1.56
diff -u -p -u -p -r1.56 amd64-tdep.c
--- gdb/amd64-tdep.c	3 Jan 2009 05:57:50 -0000	1.56
+++ gdb/amd64-tdep.c	28 Jan 2009 08:31:34 -0000
@@ -21,6 +21,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "opcode/i386.h"
+#include "dis-asm.h"
 #include "arch-utils.h"
 #include "block.h"
 #include "dummy-frame.h"
@@ -200,6 +202,42 @@ amd64_dwarf_reg_to_regnum (struct gdbarc
   return regnum;
 }
 
+/* Map architectural register numbers to gdb register numbers.  */
+
+static const int amd64_arch_regmap[16] =
+{
+  AMD64_RAX_REGNUM,	/* %rax */
+  AMD64_RCX_REGNUM,	/* %rcx */
+  AMD64_RDX_REGNUM,	/* %rdx */
+  AMD64_RBX_REGNUM,	/* %rbx */
+  AMD64_RSP_REGNUM,	/* %rsp */
+  AMD64_RBP_REGNUM,	/* %rbp */
+  AMD64_RSI_REGNUM,	/* %rsi */
+  AMD64_RDI_REGNUM,	/* %rdi */
+  AMD64_R8_REGNUM,	/* %r8 */
+  AMD64_R9_REGNUM,	/* %r9 */
+  AMD64_R10_REGNUM,	/* %r10 */
+  AMD64_R11_REGNUM,	/* %r11 */
+  AMD64_R12_REGNUM,	/* %r12 */
+  AMD64_R13_REGNUM,	/* %r13 */
+  AMD64_R14_REGNUM,	/* %r14 */
+  AMD64_R15_REGNUM	/* %r15 */
+};
+
+static const int amd64_arch_regmap_len =
+  (sizeof (amd64_arch_regmap) / sizeof (amd64_arch_regmap[0]));
+
+/* Convert architectural register number REG to the appropriate register
+   number used by GDB.  */
+
+static int
+amd64_arch_reg_to_regnum (int reg)
+{
+  gdb_assert (reg >= 0 && reg < amd64_arch_regmap_len);
+
+  return amd64_arch_regmap[reg];
+}
+
 \f
 
 /* Register classes as defined in the psABI.  */
@@ -666,7 +704,678 @@ amd64_push_dummy_call (struct gdbarch *g
   return sp + 16;
 }
 \f
+/* Displaced instruction handling.  */
+
+/* A partially decoded instruction.
+   This contains enough details for displaced stepping purposes.  */
+
+struct amd64_insn
+{
+  /* The number of opcode bytes.  */
+  int opcode_len;
+  /* The offset of the rex prefix or -1 if not present.  */
+  int rex_offset;
+  /* The offset to the first opcode byte.  */
+  int opcode_offset;
+  /* The offset to the modrm byte or -1 if not present.  */
+  int modrm_offset;
+
+  /* The raw instruction.  */
+  gdb_byte *raw_insn;
+};
+
+struct displaced_step_closure
+{
+  /* For rip-relative insns, saved copy of the reg we use instead of %rip.  */
+  int tmp_used;
+  int tmp_regno;
+  ULONGEST tmp_save;
+
+  /* Details of the instruction.  */
+  struct amd64_insn insn_details;
+
+  /* Amount of space allocated to insn_buf.  */
+  int max_len;
+
+  /* The possibly modified insn.
+     This is a variable-length field.  */
+  gdb_byte insn_buf[1];
+};
+
+/* WARNING: Keep onebyte_has_modrm, twobyte_has_modrm in sync with
+   ../opcodes/i386-dis.c (until libopcodes exports them, or an alternative,
+   at which point delete these in favor of libopcodes' versions).  */
+
+static const unsigned char onebyte_has_modrm[256] = {
+  /*	   0 1 2 3 4 5 6 7 8 9 a b c d e f	  */
+  /*	   -------------------------------	  */
+  /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */
+  /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */
+  /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */
+  /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */
+  /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */
+  /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
+  /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */
+  /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */
+  /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */
+  /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */
+  /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */
+  /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */
+  /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */
+  /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */
+  /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */
+  /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1  /* f0 */
+  /*	   -------------------------------	  */
+  /*	   0 1 2 3 4 5 6 7 8 9 a b c d e f	  */
+};
+
+static const unsigned char twobyte_has_modrm[256] = {
+  /*	   0 1 2 3 4 5 6 7 8 9 a b c d e f	  */
+  /*	   -------------------------------	  */
+  /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */
+  /* 10 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 1f */
+  /* 20 */ 1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, /* 2f */
+  /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */
+  /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */
+  /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */
+  /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */
+  /* 70 */ 1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, /* 7f */
+  /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+  /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */
+  /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */
+  /* b0 */ 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1, /* bf */
+  /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */
+  /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */
+  /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */
+  /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0  /* ff */
+  /*	   -------------------------------	  */
+  /*	   0 1 2 3 4 5 6 7 8 9 a b c d e f	  */
+};
+
+static int amd64_syscall_p (const struct amd64_insn *insn, int *lengthp);
+
+static int
+rex_prefix_p (gdb_byte pfx)
+{
+  return REX_PREFIX_P (pfx);
+}
+
+/* Skip the legacy instruction prefixes in INSN.
+   We assume INSN is properly sentineled so we don't have to worry
+   about falling off the end of the buffer.  */
+
+static gdb_byte *
+skip_prefixes (gdb_byte *insn)
+{
+  while (1)
+    {
+      switch (*insn)
+	{
+	case DATA_PREFIX_OPCODE:
+	case ADDR_PREFIX_OPCODE:
+	case CS_PREFIX_OPCODE:
+	case DS_PREFIX_OPCODE:
+	case ES_PREFIX_OPCODE:
+	case FS_PREFIX_OPCODE:
+	case GS_PREFIX_OPCODE:
+	case SS_PREFIX_OPCODE:
+	case LOCK_PREFIX_OPCODE:
+	case REPE_PREFIX_OPCODE:
+	case REPNE_PREFIX_OPCODE:
+	  ++insn;
+	  continue;
+	default:
+	  break;
+	}
+      break;
+    }
+
+  return insn;
+}
+
+/* fprintf-function for amd64_insn_length.
+   This function is a nop, we don't want to print anything, we just want to
+   compute the length of the insn.  */
+
+static int ATTR_FORMAT (printf, 2, 3)
+amd64_insn_length_fprintf (void *stream, const char *format, ...)
+{
+  return 0;
+}
+
+/* Initialize a struct disassemble_info for amd64_insn_length.	*/
+
+static void
+amd64_insn_length_init_dis (struct gdbarch *gdbarch,
+			    struct disassemble_info *di,
+			    const gdb_byte *insn, int max_len,
+			    CORE_ADDR addr)
+{
+  init_disassemble_info (di, NULL, amd64_insn_length_fprintf);
+
+  /* init_disassemble_info installs buffer_read_memory, etc.
+     so we don't need to do that here.
+     The cast is necessary until disassemble_info is const-ified.  */
+  di->buffer = (gdb_byte *) insn;
+  di->buffer_length = max_len;
+  di->buffer_vma = addr;
+
+  di->arch = gdbarch_bfd_arch_info (gdbarch)->arch;
+  di->mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  di->endian = gdbarch_byte_order (gdbarch);
+  di->endian_code = gdbarch_byte_order_for_code (gdbarch);
+
+  disassemble_init_for_target (di);
+}
+
+/* Return the length in bytes of INSN.
+   MAX_LEN is the size of the buffer containing INSN.
+   libopcodes currently doesn't export a utility to compute the
+   instruction length, so use the disassembler until then.  */
+
+static int
+amd64_insn_length (struct gdbarch *gdbarch,
+		   const gdb_byte *insn, int max_len, CORE_ADDR addr)
+{
+  struct disassemble_info di;
+
+  amd64_insn_length_init_dis (gdbarch, &di, insn, max_len, addr);
+
+  return gdbarch_print_insn (gdbarch, addr, &di);
+}
+
+/* Return an integer register (other than RSP) that is unused as an input
+   operand in INSN.
+   In order to not require adding a rex prefix if the insn doesn't already
+   have one, the result is restricted to RAX ... RDI, sans RSP.
+   The register numbering of the result follows architecture ordering,
+   e.g. RDI = 7.  */
+
+static int
+amd64_get_unused_input_int_reg (const struct amd64_insn *details)
+{
+  /* 1 bit for each reg */
+  int used_regs_mask = 0;
+
+  /* There can be at most 3 int regs used as inputs in an insn, and we have
+     7 to choose from (RAX ... RDI, sans RSP).
+     This allows us to take a conservative approach and keep things simple.
+     E.g. By avoiding RAX, we don't have to specifically watch for opcodes
+     that implicitly specify RAX.  */
+
+  /* Avoid RAX.  */
+  used_regs_mask |= 1 << EAX_REG_NUM;
+  /* Similarily avoid RDX, implicit operand in divides.  */
+  used_regs_mask |= 1 << EDX_REG_NUM;
+  /* Avoid RSP.  */
+  used_regs_mask |= 1 << ESP_REG_NUM;
+
+  /* If the opcode is one byte long and there's no ModRM byte,
+     assume the opcode specifies a register.  */
+  if (details->opcode_len == 1 && details->modrm_offset == -1)
+    used_regs_mask |= 1 << (details->raw_insn[details->opcode_offset] & 7);
+
+  /* Mark used regs in the modrm/sib bytes.  */
+  if (details->modrm_offset != -1)
+    {
+      int modrm = details->raw_insn[details->modrm_offset];
+      int mod = MODRM_MOD_FIELD (modrm);
+      int reg = MODRM_REG_FIELD (modrm);
+      int rm = MODRM_RM_FIELD (modrm);
+      int have_sib = mod != 3 && rm == 4;
+
+      /* Assume the reg field of the modrm byte specifies a register.  */
+      used_regs_mask |= 1 << ((modrm >> 3) & 3);
+
+      if (have_sib)
+	{
+	  int base = SIB_BASE_FIELD (details->raw_insn[details->modrm_offset + 1]);
+	  int index = SIB_INDEX_FIELD (details->raw_insn[details->modrm_offset + 1]);
+	  used_regs_mask |= 1 << base;
+	  used_regs_mask |= 1 << index;
+	}
+      else
+	{
+	  used_regs_mask |= 1 << rm;
+	}
+    }
+
+  gdb_assert (used_regs_mask < 256);
+  gdb_assert (used_regs_mask != 255);
+
+  /* Finally, find a free reg.  */
+  {
+    int i;
+
+    for (i = 0; i < 8; ++i)
+      {
+	if (! (used_regs_mask & (1 << i)))
+	  return i;
+      }
+
+    /* We shouldn't get here.  */
+    internal_error (__FILE__, __LINE__, _("unable to find free reg"));
+  }
+}
+
+/* Extract the details of INSN that we need.  */
+
+static void
+amd64_get_insn_details (gdb_byte *insn, struct amd64_insn *details)
+{
+  gdb_byte *start = insn;
+  int need_modrm;
+
+  details->raw_insn = insn;
+
+  details->opcode_len = -1;
+  details->rex_offset = -1;
+  details->opcode_offset = -1;
+  details->modrm_offset = -1;
+
+  /* Skip legacy instruction prefixes.  */
+  insn = skip_prefixes (insn);
+
+  /* Skip REX instruction prefix.  */
+  if (rex_prefix_p (*insn))
+    {
+      details->rex_offset = insn - start;
+      ++insn;
+    }
+
+  details->opcode_offset = insn - start;
+
+  if (*insn == TWO_BYTE_OPCODE_ESCAPE)
+    {
+      /* Two or three-byte opcode.  */
+      ++insn;
+      need_modrm = twobyte_has_modrm[*insn];
+
+      /* Check for three-byte opcode.  */
+      if (*insn == 0x38 || *insn == 0x3a)
+	{
+	  ++insn;
+	  details->opcode_len = 3;
+	}
+      else
+	details->opcode_len = 2;
+    }
+  else
+    {
+      /* One-byte opcode.  */
+      need_modrm = onebyte_has_modrm[*insn];
+      details->opcode_len = 1;
+    }
+
+  if (need_modrm)
+    {
+      ++insn;
+      details->modrm_offset = insn - start;
+    }
+}
+
+/* Update %rip-relative addressing in INSN.
+
+   %rip-relative addressing only uses a 32-bit displacement.
+   32 bits is not enough to be guaranteed to cover the distance between where
+   the real instruction is and where its copy is.
+   Convert the insn to use base+disp addressing.
+   We set base = pc + insn_length so we can leave disp unchanged.  */
+
+static void
+fixup_riprel (struct gdbarch *gdbarch, struct displaced_step_closure *dsc,
+	      CORE_ADDR from, CORE_ADDR to, struct regcache *regs)
+{
+  const struct amd64_insn *insn_details = &dsc->insn_details;
+  int modrm_offset = insn_details->modrm_offset;
+  gdb_byte *insn = insn_details->raw_insn + modrm_offset;
+  CORE_ADDR rip_base;
+  int32_t disp;
+  int insn_length;
+  int arch_tmp_regno, tmp_regno;
+  ULONGEST orig_value;
+
+  /* %rip+disp32 addressing mode, displacement follows ModRM byte.  */
+  ++insn;
+
+  /* Compute the rip-relative address.	*/
+  disp = extract_signed_integer (insn, sizeof (int32_t));
+  insn_length = amd64_insn_length (gdbarch, dsc->insn_buf, dsc->max_len, from);
+  rip_base = from + insn_length;
+
+  /* We need a register to hold the address.
+     Pick one not used in the insn.
+     NOTE: arch_tmp_regno uses architecture ordering, e.g. RDI = 7.  */
+  arch_tmp_regno = amd64_get_unused_input_int_reg (insn_details);
+  tmp_regno = amd64_arch_reg_to_regnum (arch_tmp_regno);
+
+  /* REX.B should be unset as we were using rip-relative addressing,
+     but ensure it's unset anyway, tmp_regno is not r8-r15.  */
+  if (insn_details->rex_offset != -1)
+    dsc->insn_buf[insn_details->rex_offset] &= ~REX_B;
+
+  regcache_cooked_read_unsigned (regs, tmp_regno, &orig_value);
+  dsc->tmp_regno = tmp_regno;
+  dsc->tmp_save = orig_value;
+  dsc->tmp_used = 1;
+
+  /* Convert the ModRM field to be base+disp.  */
+  dsc->insn_buf[modrm_offset] &= ~0xc7;
+  dsc->insn_buf[modrm_offset] |= 0x80 + arch_tmp_regno;
+
+  regcache_cooked_write_unsigned (regs, tmp_regno, rip_base);
+
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog, "displaced: %%rip-relative addressing used.\n"
+			"displaced: using temp reg %d, old value 0x%s, new value 0x%s\n",
+			dsc->tmp_regno, paddr_nz (dsc->tmp_save),
+			paddr_nz (rip_base));
+}
+
+static void
+fixup_displaced_copy (struct gdbarch *gdbarch,
+		      struct displaced_step_closure *dsc,
+		      CORE_ADDR from, CORE_ADDR to, struct regcache *regs)
+{
+  const struct amd64_insn *details = &dsc->insn_details;
+
+  if (details->modrm_offset != -1)
+    {
+      gdb_byte modrm = details->raw_insn[details->modrm_offset];
+
+      if ((modrm & 0xc7) == 0x05)
+	{
+	  /* The insn uses rip-relative addressing.
+	     Deal with it.  */
+	  fixup_riprel (gdbarch, dsc, from, to, regs);
+	}
+    }
+}
+
+struct displaced_step_closure *
+amd64_displaced_step_copy_insn (struct gdbarch *gdbarch,
+				CORE_ADDR from, CORE_ADDR to,
+				struct regcache *regs)
+{
+  int len = gdbarch_max_insn_length (gdbarch);
+  /* Extra space for sentinels so fixup_{riprel,displaced_copy don't have to
+     continually watch for running off the end of the buffer.  */
+  int fixup_sentinel_space = len;
+  struct displaced_step_closure *dsc =
+    xmalloc (sizeof (*dsc) + len + fixup_sentinel_space);
+  gdb_byte *buf = &dsc->insn_buf[0];
+  struct amd64_insn *details = &dsc->insn_details;
+
+  dsc->tmp_used = 0;
+  dsc->max_len = len + fixup_sentinel_space;
+
+  read_memory (from, 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);
+
+  amd64_get_insn_details (buf, details);
+
+  /* GDB may get control back after the insn after the syscall.
+     Presumably this is a kernel bug.
+     If this is a syscall, make sure there's a nop afterwards.  */
+  {
+    int syscall_length;
+
+    if (amd64_syscall_p (details, &syscall_length))
+      buf[details->opcode_offset + syscall_length] = NOP_OPCODE;
+  }
+
+  /* Modify the insn to cope with the address where it will be executed from.
+     In particular, handle any rip-relative addressing.	 */
+  fixup_displaced_copy (gdbarch, dsc, from, to, regs);
+
+  write_memory (to, buf, len);
+
+  if (debug_displaced)
+    {
+      fprintf_unfiltered (gdb_stdlog, "displaced: copy 0x%s->0x%s: ",
+			  paddr_nz (from), paddr_nz (to));
+      displaced_step_dump_bytes (gdb_stdlog, buf, len);
+    }
+
+  return dsc;
+}
+
+static int
+amd64_absolute_jmp_p (const struct amd64_insn *details)
+{
+  const gdb_byte *insn = &details->raw_insn[details->opcode_offset];
+
+  if (insn[0] == 0xff)
+    {
+      /* jump near, absolute indirect (/4) */
+      if ((insn[1] & 0x38) == 0x20)
+	return 1;
+
+      /* jump far, absolute indirect (/5) */
+      if ((insn[1] & 0x38) == 0x28)
+	return 1;
+    }
+
+  return 0;
+}
+
+static int
+amd64_absolute_call_p (const struct amd64_insn *details)
+{
+  const gdb_byte *insn = &details->raw_insn[details->opcode_offset];
+
+  if (insn[0] == 0xff)
+    {
+      /* Call near, absolute indirect (/2) */
+      if ((insn[1] & 0x38) == 0x10)
+	return 1;
+
+      /* Call far, absolute indirect (/3) */
+      if ((insn[1] & 0x38) == 0x18)
+	return 1;
+    }
+
+  return 0;
+}
+
+static int
+amd64_ret_p (const struct amd64_insn *details)
+{
+  /* NOTE: gcc can emit "repz ; ret".  */
+  const gdb_byte *insn = &details->raw_insn[details->opcode_offset];
+
+  switch (insn[0])
+    {
+    case 0xc2: /* ret near, pop N bytes */
+    case 0xc3: /* ret near */
+    case 0xca: /* ret far, pop N bytes */
+    case 0xcb: /* ret far */
+    case 0xcf: /* iret */
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+static int
+amd64_call_p (const struct amd64_insn *details)
+{
+  const gdb_byte *insn = &details->raw_insn[details->opcode_offset];
 
+  if (amd64_absolute_call_p (details))
+    return 1;
+
+  /* call near, relative */
+  if (insn[0] == 0xe8)
+    return 1;
+
+  return 0;
+}
+
+static int
+amd64_breakpoint_p (const struct amd64_insn *details)
+{
+  const gdb_byte *insn = &details->raw_insn[details->opcode_offset];
+
+  return insn[0] == 0xcc; /* int 3 */
+}
+
+/* Return non-zero if INSN is a system call, and set *LENGTHP to its
+   length in bytes.  Otherwise, return zero.  */
+
+static int
+amd64_syscall_p (const struct amd64_insn *details, int *lengthp)
+{
+  const gdb_byte *insn = &details->raw_insn[details->opcode_offset];
+
+  if (insn[0] == 0x0f && insn[1] == 0x05)
+    {
+      *lengthp = 2;
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Fix up the state of registers and memory after having single-stepped
+   a displaced instruction.  */
+
+void
+amd64_displaced_step_fixup (struct gdbarch *gdbarch,
+			    struct displaced_step_closure *dsc,
+			    CORE_ADDR from, CORE_ADDR to,
+			    struct regcache *regs)
+{
+  /* The offset we applied to the instruction's address.  */
+  ULONGEST insn_offset = to - from;
+  gdb_byte *insn = dsc->insn_buf;
+  const struct amd64_insn *insn_details = &dsc->insn_details;
+
+  if (debug_displaced)
+    fprintf_unfiltered (gdb_stdlog,
+			"displaced: fixup (0x%s, 0x%s), "
+			"insn = 0x%02x 0x%02x ...\n",
+			paddr_nz (from), paddr_nz (to), insn[0], insn[1]);
+
+  /* If we used a tmp reg, restore it.	*/
+
+  if (dsc->tmp_used)
+    {
+      if (debug_displaced)
+	fprintf_unfiltered (gdb_stdlog, "displaced: restoring reg %d to 0x%s\n",
+			    dsc->tmp_regno, paddr_nz (dsc->tmp_save));
+      regcache_cooked_write_unsigned (regs, dsc->tmp_regno, dsc->tmp_save);
+    }
+
+  /* The list of issues to contend with here is taken from
+     resume_execution in arch/x86/kernel/kprobes.c, Linux 2.6.28.
+     Yay for Free Software!  */
+
+  /* Relocate the %rip back to the program's instruction stream,
+     if necessary.  */
+
+  /* Except in the case of absolute or indirect jump or call
+     instructions, or a return instruction, the new rip is relative to
+     the displaced instruction; make it relative to the original insn.
+     Well, signal handler returns don't need relocation either, but we use the
+     value of %rip to recognize those; see below.  */
+  if (! amd64_absolute_jmp_p (insn_details)
+      && ! amd64_absolute_call_p (insn_details)
+      && ! amd64_ret_p (insn_details))
+    {
+      ULONGEST orig_rip;
+      int insn_len;
+
+      regcache_cooked_read_unsigned (regs, AMD64_RIP_REGNUM, &orig_rip);
+
+      /* A signal trampoline system call changes the %rip, resuming
+	 execution of the main program after the signal handler has
+	 returned.  That makes them like 'return' instructions; we
+	 shouldn't relocate %rip.
+
+	 But most system calls don't, and we do need to relocate %rip.
+
+	 Our heuristic for distinguishing these cases: if stepping
+	 over the system call instruction left control directly after
+	 the instruction, the we relocate --- control almost certainly
+	 doesn't belong in the displaced copy.	Otherwise, we assume
+	 the instruction has put control where it belongs, and leave
+	 it unrelocated.  Goodness help us if there are PC-relative
+	 system calls.	*/
+      if (amd64_syscall_p (insn_details, &insn_len)
+	  && orig_rip != to + insn_len
+	  /* GDB can get control back after the insn after the syscall.
+	     Presumably this is a kernel bug.
+	     Fixup ensures its a nop, we add one to the length for it.  */
+	  && orig_rip != to + insn_len + 1)
+	{
+	  if (debug_displaced)
+	    fprintf_unfiltered (gdb_stdlog,
+				"displaced: syscall changed %%rip; "
+				"not relocating\n");
+	}
+      else
+	{
+	  ULONGEST rip = orig_rip - insn_offset;
+
+	  /* If we have stepped over a breakpoint, set %rip to
+	     point at the breakpoint instruction itself.
+
+	     (gdbarch_decr_pc_after_break was never something the core
+	     of GDB should have been concerned with; arch-specific
+	     code should be making PC values consistent before
+	     presenting them to GDB.)  */
+	  if (amd64_breakpoint_p (insn_details))
+	    {
+	      if (debug_displaced)
+		fprintf_unfiltered (gdb_stdlog,
+				    "displaced: stepped breakpoint\n");
+	      rip--;
+	    }
+
+	  regcache_cooked_write_unsigned (regs, AMD64_RIP_REGNUM, rip);
+
+	  if (debug_displaced)
+	    fprintf_unfiltered (gdb_stdlog,
+				"displaced: "
+				"relocated %%rip from 0x%s to 0x%s\n",
+				paddr_nz (orig_rip), paddr_nz (rip));
+	}
+    }
+
+  /* If the instruction was PUSHFL, then the TF bit will be set in the
+     pushed value, and should be cleared.  We'll leave this for later,
+     since GDB already messes up the TF flag when stepping over a
+     pushfl.  */
+
+  /* If the instruction was a call, the return address now atop the
+     stack is the address following the copied instruction.  We need
+     to make it the address following the original instruction.	 */
+  if (amd64_call_p (insn_details))
+    {
+      ULONGEST rsp;
+      ULONGEST retaddr;
+      const ULONGEST retaddr_len = 8;
+
+      regcache_cooked_read_unsigned (regs, AMD64_RSP_REGNUM, &rsp);
+      retaddr = read_memory_unsigned_integer (rsp, retaddr_len);
+      retaddr = (retaddr - insn_offset) & 0xffffffffUL;
+      write_memory_unsigned_integer (rsp, retaddr_len, retaddr);
+
+      if (debug_displaced)
+	fprintf_unfiltered (gdb_stdlog,
+			    "displaced: relocated return addr at 0x%s "
+			    "to 0x%s\n",
+			    paddr_nz (rsp),
+			    paddr_nz (retaddr));
+    }
+}
+\f
 /* The maximum number of saved registers.  This should include %rip.  */
 #define AMD64_NUM_SAVED_REGS	AMD64_NUM_GREGS
 
@@ -756,24 +1465,6 @@ amd64_analyze_stack_align (CORE_ADDR pc,
   gdb_byte buf[18];
   int reg, r;
   int offset, offset_and;
-  static int regnums[16] = {
-    AMD64_RAX_REGNUM,		/* %rax */
-    AMD64_RCX_REGNUM,		/* %rcx */
-    AMD64_RDX_REGNUM,		/* %rdx */
-    AMD64_RBX_REGNUM,		/* %rbx */
-    AMD64_RSP_REGNUM,		/* %rsp */
-    AMD64_RBP_REGNUM,		/* %rbp */
-    AMD64_RSI_REGNUM,		/* %rsi */
-    AMD64_RDI_REGNUM,		/* %rdi */
-    AMD64_R8_REGNUM,		/* %r8 */
-    AMD64_R9_REGNUM,		/* %r9 */
-    AMD64_R10_REGNUM,		/* %r10 */
-    AMD64_R11_REGNUM,		/* %r11 */
-    AMD64_R12_REGNUM,		/* %r12 */
-    AMD64_R13_REGNUM,		/* %r13 */
-    AMD64_R14_REGNUM,		/* %r14 */
-    AMD64_R15_REGNUM,		/* %r15 */
-  };
 
   if (target_read_memory (pc, buf, sizeof buf))
     return pc;
@@ -889,7 +1580,7 @@ amd64_analyze_stack_align (CORE_ADDR pc,
     return pc;
 
   if (current_pc > pc + offset_and)
-    cache->saved_sp_reg = regnums[reg];
+    cache->saved_sp_reg = amd64_arch_reg_to_regnum (reg);
 
   return min (pc + offset + 2, current_pc);
 }
Index: gdb/amd64-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/amd64-tdep.h,v
retrieving revision 1.13
diff -u -p -u -p -r1.13 amd64-tdep.h
--- gdb/amd64-tdep.h	3 Jan 2009 05:57:50 -0000	1.13
+++ gdb/amd64-tdep.h	28 Jan 2009 08:31:34 -0000
@@ -67,6 +67,14 @@ enum amd64_regnum
 /* Number of general purpose registers.  */
 #define AMD64_NUM_GREGS		24
 
+extern struct displaced_step_closure *amd64_displaced_step_copy_insn
+  (struct gdbarch *gdbarch, CORE_ADDR from, CORE_ADDR to,
+   struct regcache *regs);
+extern void amd64_displaced_step_fixup (struct gdbarch *gdbarch,
+					struct displaced_step_closure *closure,
+					CORE_ADDR from, CORE_ADDR to,
+					struct regcache *regs);
+
 extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
 
 /* Functions from amd64-tdep.c which may be needed on architectures
Index: gdb/testsuite/gdb.arch/amd64-disp-step.S
===================================================================
RCS file: gdb/testsuite/gdb.arch/amd64-disp-step.S
diff -N gdb/testsuite/gdb.arch/amd64-disp-step.S
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.arch/amd64-disp-step.S	28 Jan 2009 08:31:35 -0000
@@ -0,0 +1,153 @@
+/* Copyright 2009 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/>.
+
+   This file is part of the gdb testsuite.
+   It tests displaced stepping over various insns that require special
+   handling.  */
+
+	.text
+
+	.global main
+main:
+	nop
+
+/* test call/ret */
+
+	.global test_call
+test_call:
+	call test_call_subr
+	nop
+	.global test_ret_end
+test_ret_end:
+	nop
+
+/* test abs-jmp/rep-ret */
+
+test_abs_jmp_setup:
+	mov $test_abs_jmp_return,%rdx
+	push %rdx
+	mov $test_abs_jmp_subr,%rdx
+	.global test_abs_jmp
+test_abs_jmp:
+	jmp *%rdx
+test_abs_jmp_return:
+	nop
+	.global test_rep_ret_end
+test_rep_ret_end:
+	nop
+
+/* test syscall */
+
+	.global test_syscall
+	mov $0x27,%eax /* getpid */
+test_syscall:
+	syscall
+	nop
+test_syscall_end:
+	nop
+
+/* test rip-relative
+   GDB picks a spare register to hold the rip-relative address.
+   Exercise all the possibilities (rax-rdi, sans rsp).  */
+
+	.global test_rip_rax
+test_rip_rax:
+	add answer(%rip),%rax
+	.global test_rip_rax_end
+test_rip_rax_end:
+	nop
+
+	.global test_rip_rbx
+test_rip_rbx:
+	add answer(%rip),%rbx
+	.global test_rip_rbx_end
+test_rip_rbx_end:
+	nop
+
+	.global test_rip_rcx
+test_rip_rcx:
+	add answer(%rip),%rcx
+	.global test_rip_rcx_end
+test_rip_rcx_end:
+	nop
+
+	.global test_rip_rdx
+test_rip_rdx:
+	add answer(%rip),%rdx
+	.global test_rip_rdx_end
+test_rip_rdx_end:
+	nop
+
+	.global test_rip_rbp
+test_rip_rbp:
+	add answer(%rip),%rbp
+	.global test_rip_rbp_end
+test_rip_rbp_end:
+	nop
+
+	.global test_rip_rsi
+test_rip_rsi:
+	add answer(%rip),%rsi
+	.global test_rip_rsi_end
+test_rip_rsi_end:
+	nop
+
+	.global test_rip_rdi
+test_rip_rdi:
+	add answer(%rip),%rdi
+	.global test_rip_rdi_end
+test_rip_rdi_end:
+	nop
+
+	/* skip over test data */
+	jmp done
+
+/* test rip-relative data */
+
+answer:	.8byte 42
+
+/* all done */
+
+done:
+	mov $0,%rdi
+	call exit
+	hlt
+
+/***********************************************/
+
+/* subroutine to help test call/ret */
+
+test_call_subr:
+	nop
+	.global test_call_end
+test_call_end:
+	nop
+
+	.global test_ret
+test_ret:
+	ret
+
+/* subroutine to help test abs-jmp/rep-ret */
+
+test_abs_jmp_subr:
+	nop
+	.global test_abs_jmp_end
+test_abs_jmp_end:
+	nop
+
+	.global test_rep_ret
+test_rep_ret:
+	repz
+	ret
Index: gdb/testsuite/gdb.arch/amd64-disp-step.exp
===================================================================
RCS file: gdb/testsuite/gdb.arch/amd64-disp-step.exp
diff -N gdb/testsuite/gdb.arch/amd64-disp-step.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.arch/amd64-disp-step.exp	28 Jan 2009 08:31:35 -0000
@@ -0,0 +1,219 @@
+# Copyright 2009 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/>.
+
+# This file is part of the gdb testsuite.
+
+# Test amd64 displaced stepping.
+
+if $tracelevel {
+    strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+if ![istarget "x86_64-*-linux*"] then {
+    verbose "Skipping x86_64 displaced stepping tests."
+    return
+}
+
+set newline "\[\r\n\]*"
+
+set testfile "amd64-disp-step"
+set srcfile ${testfile}.S
+set binfile ${objdir}/${subdir}/${testfile}
+
+set additional_flags "-Wa,-g"
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $additional_flags]] != "" } {
+    untested amd64-disp-step.exp
+    return -1
+}
+
+# Get things started.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test "set displaced-stepping on" ""
+gdb_test "show displaced-stepping" ".* displaced stepping .* is on.*"
+
+if ![runto_main] then {
+    fail "Can't run to main"
+    return 0
+}
+
+##########################################
+
+# Test call/ret.
+
+gdb_test "break test_call" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_call"
+gdb_test "break test_call_end" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_call_end"
+
+gdb_test "break test_ret" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_ret"
+gdb_test "break test_ret_end" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_ret_end"
+
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_call ().*" \
+    "continue to test_call"
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_call_end ().*" \
+    "continue to test_call_end"
+
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_ret ().*" \
+    "continue to test_ret"
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_ret_end ().*" \
+    "continue to test_ret_end"
+
+##########################################
+
+# Test abs-jmp/rep-ret.
+
+gdb_test "break test_abs_jmp" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_abs_jmp"
+gdb_test "break test_abs_jmp_end" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_abs_jmp_end"
+
+gdb_test "break test_rep_ret" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_rep_ret"
+gdb_test "break test_rep_ret_end" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_rep_ret_end"
+
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_abs_jmp ().*" \
+    "continue to test_abs_jmp"
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_abs_jmp_end ().*" \
+    "continue to test_abs_jmp_end"
+
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_rep_ret ().*" \
+    "continue to test_rep_ret"
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_rep_ret_end ().*" \
+    "continue to test_rep_ret_end"
+
+##########################################
+
+# Test syscall.
+
+gdb_test "break test_syscall" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_syscall"
+gdb_test "break test_syscall_end" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_syscall_end"
+
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_syscall ().*" \
+    "continue to test_syscall"
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_syscall_end ().*" \
+    "continue to test_syscall_end"
+
+##########################################
+
+# Test rip-relative.
+# GDB picks a spare register to hold the rip-relative address.
+# Exercise all the possibilities (rax-rdi, sans rsp).
+
+# The order must much the order in srcfile.
+set rip_regs { "rax" "rbx" "rcx" "rdx" "rbp" "rsi" "rdi" }
+
+# Assign val to all specified regs.
+
+proc set_regs { regs val } {
+    global gdb_prompt
+
+    foreach reg ${regs} {
+	# Use send_gdb/gdb_expect so that these aren't logged as pass/fail.
+	send_gdb "set \$${reg} = ${val}\n"
+	gdb_expect 10 {
+	    -re "$gdb_prompt $" { 
+		verbose "Setting ${reg} to ${val}." 2
+	    }
+	    timeout {
+		warning "Couldn't set ${reg} to ${val}."
+	    }
+	}
+    }
+}
+
+# Verify all REGS equal VAL, except REG which equals REG_VAL.
+
+proc verify_regs { test_name regs val except_reg except_reg_val } {
+    global newline
+
+    foreach reg ${regs} {
+	set expected ${val}
+	if { "${reg}" == "${except_reg}" } {
+	    set expected ${except_reg_val}
+	}
+	# The cast to (int) is because RBP is printed as a pointer.
+	gdb_test "p (int) \$${reg}" " = ${expected}${newline}" "${test_name} ${reg} expected value"
+    }
+}
+
+proc rip_test { reg } {
+    global srcfile rip_regs
+
+    set test_start_label "test_rip_${reg}"
+    set test_end_label "test_rip_${reg}_end"
+
+    gdb_test "break ${test_start_label}" \
+	"Breakpoint.*at.* file .*$srcfile, line.*" \
+	"break ${test_start_label}"
+    gdb_test "break ${test_end_label}" \
+	"Breakpoint.*at.* file .*$srcfile, line.*" \
+	"break ${test_end_label}"
+
+    gdb_test "continue" \
+	"Continuing.*Breakpoint.*, ${test_start_label} ().*" \
+	"continue to ${test_start_label}"
+
+    set_regs ${rip_regs} 0
+
+    gdb_test "continue" \
+	"Continuing.*Breakpoint.*, ${test_end_label} ().*" \
+	"continue to ${test_end_label}"
+
+    verify_regs "test rip w/${reg}" ${rip_regs} 0 ${reg} 42
+}
+
+foreach reg ${rip_regs} {
+    rip_test $reg
+}
+
+##########################################
+
+# Done, run program to exit.
+
+gdb_continue_to_end "amd64-disp-step"
Index: gdb/testsuite/gdb.arch/i386-disp-step.S
===================================================================
RCS file: gdb/testsuite/gdb.arch/i386-disp-step.S
diff -N gdb/testsuite/gdb.arch/i386-disp-step.S
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.arch/i386-disp-step.S	28 Jan 2009 08:31:35 -0000
@@ -0,0 +1,64 @@
+/* Copyright 2009 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/>.
+
+   This file is part of the gdb testsuite.
+   It tests displaced stepping over various insns that require special
+   handling.  */
+
+	.text
+
+	.global main
+main:
+	nop
+
+/* test call/ret */
+
+	.global test_call
+test_call:
+	call test_call_subr
+	nop
+	.global test_ret_end
+test_ret_end:
+	nop
+
+/* test syscall */
+
+	.global test_syscall
+	mov $0x14,%eax /* getpid */
+test_syscall:
+	int $0x80
+	nop
+test_syscall_end:
+	nop
+
+/* all done */
+
+	pushl $0
+	call exit
+	hlt
+
+/***********************************************/
+
+/* subroutine to help test call/ret */
+
+test_call_subr:
+	nop
+	.global test_call_end
+test_call_end:
+	nop
+
+	.global test_ret
+test_ret:
+	ret
Index: gdb/testsuite/gdb.arch/i386-disp-step.exp
===================================================================
RCS file: gdb/testsuite/gdb.arch/i386-disp-step.exp
diff -N gdb/testsuite/gdb.arch/i386-disp-step.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.arch/i386-disp-step.exp	28 Jan 2009 08:31:35 -0000
@@ -0,0 +1,112 @@
+# Copyright 2009 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/>.
+
+# This file is part of the gdb testsuite.
+
+# Test i386 displaced stepping.
+
+if $tracelevel {
+    strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+if ![istarget "i?86-*-linux*"] then {
+    verbose "Skipping x86 displaced stepping tests."
+    return
+}
+
+set testfile "i386-disp-step"
+set srcfile ${testfile}.S
+set binfile ${objdir}/${subdir}/${testfile}
+
+set additional_flags "-Wa,-g"
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $additional_flags]] != "" } {
+    untested i386-disp-step.exp
+    return -1
+}
+
+# Get things started.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test "set displaced-stepping on" ""
+gdb_test "show displaced-stepping" ".* displaced stepping .* is on.*"
+
+if ![runto_main] then {
+    fail "Can't run to main"
+    return 0
+}
+
+##########################################
+
+# Test call/ret.
+
+gdb_test "break test_call" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_call"
+gdb_test "break test_call_end" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_call_end"
+
+gdb_test "break test_ret" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_ret"
+gdb_test "break test_ret_end" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_ret_end"
+
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_call ().*" \
+    "continue to test_call"
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_call_end ().*" \
+    "continue to test_call_end"
+
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_ret ().*" \
+    "continue to test_ret"
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_ret_end ().*" \
+    "continue to test_ret_end"
+
+##########################################
+
+# Test syscall.
+
+gdb_test "break test_syscall" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_syscall"
+gdb_test "break test_syscall_end" \
+    "Breakpoint.*at.* file .*$srcfile, line.*" \
+    "break test_syscall_end"
+
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_syscall ().*" \
+    "continue to test_syscall"
+gdb_test "continue" \
+    "Continuing.*Breakpoint.*, test_syscall_end ().*" \
+    "continue to test_syscall_end"
+
+##########################################
+
+# Done, run program to exit.
+
+gdb_continue_to_end "i386-disp-step"

  reply	other threads:[~2009-01-28  8:40 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-27  1:33 Doug Evans
2009-01-27  8:26 ` Stan Shebs
2009-01-27 17:27 ` Pedro Alves
2009-01-28 12:39   ` Doug Evans [this message]
2009-01-28 14:34     ` Pedro Alves
2009-01-28 15:05     ` Daniel Jacobowitz
2009-01-27 20:27 ` Daniel Jacobowitz
2009-01-28  0:13   ` Doug Evans
2009-01-28 14:37     ` Daniel Jacobowitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e394668d0901280039s4fc7e2ch460040bd09127770@mail.gmail.com \
    --to=dje@google.com \
    --cc=gdb-patches@sourceware.org \
    --cc=pedro@codesourcery.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox