Implement displaced stepping.

gdb/
	* gdbarch.sh (max_insn_length): New 'variable'.
	(displaced_step_copy, displaced_step_fixup)
	(displaced_step_free_closure, displaced_step_location): New
	functions.
	(struct displaced_step_closure): Add forward declaration.
	* gdbarch.c, gdbarch.h: Regenerated.

	* arch-utils.c: #include "objfiles.h".
	(simple_displaced_step_copy_insn)
	(simple_displaced_step_free_closure)
	(displaced_step_at_entry_point): New functions.
	* arch-utils.h (simple_displaced_step_copy_insn)
	(simple_displaced_step_free_closure)
	(displaced_step_at_entry_point): New prototypes.

	* i386-tdep.c (I386_MAX_INSN_LEN): Rename to...
	(I386_MAX_MATCHED_INSN_LEN): ... this.
	(i386_absolute_jmp_p, i386_absolute_call_p)
	(i386_ret_p, i386_call_p, i386_breakpoint_p, i386_syscall_p)
	(i386_displaced_step_fixup): New functions.
	(struct i386_insn, i386_match_insn): Update.
	(i386_gdbarch_init): Set gdbarch_max_insn_length.
	* i386-tdep.h (I386_MAX_INSN_LEN): New.
	(i386_displaced_step_fixup): New prototype.
	* i386-linux-tdep.c (i386_linux_init_abi): Include "arch-utils.h".
	Register gdbarch_displaced_step_copy,
	gdbarch_displaced_step_fixup, gdbarch_displaced_step_free_closure,
	and gdbarch_displaced_step_location functions.

	* infrun.c (debug_displaced): New variable.
	(show_debug_displaced): New function.
	(struct displaced_step_request): New struct.
	(displaced_step_request_queue, displaced_step_ptid)
	(displaced_step_gdbarch, displaced_step_closure)
	(displaced_step_original, displaced_step_copy)
	(displaced_step_saved_copy, can_use_displaced_stepping): New
	variables.
	(show_can_use_displaced_stepping, use_displaced_stepping)
	(displaced_step_clear, cleanup_displaced_step_closure)
	(displaced_step_dump_bytes, displaced_step_prepare)
	(displaced_step_clear_cleanup, write_memory_ptid)
	(displaced_step_fixup): New functions.
	(resume): Call displaced_step_prepare.
	(proceed): Call read_pc once, and remember the value.  If using
	displaced stepping, don't remove breakpoints.
	(handle_inferior_event): Call displaced_step_fixup.  Add some
	debugging output.  When we try to step over a breakpoint, but get
	a signal to deliver to the thread instead, ensure the step-resume
	breakpoint is actually inserted.  If a thread hop is needed, and
	displaced stepping is enabled, don't remove breakpoints.
	(init_wait_for_inferior): Call displaced_step_clear.
	(_initialize_infrun): Add "set debug displaced" command.  Add
	"maint set can-use-displaced-stepping" command.  Clear
	displaced_step_ptid.
	* inferior.h (debug_displaced): Declare variable.
	(displaced_step_dump_bytes): Declare function.

	* Makefile.in (arch-utils.o, i386-linux-tdep.o): Update
	dependencies.

	gdb/testsuite/
	* gdb.asm/asmsrc1.s: Add scratch space.

	gdb/doc/
	* gdb.texinfo (Debugging Output): Document "set/show debug
	displaced".
	(Maintenance Commands): Document "maint set/show
	can-use-displaced-stepping".
This commit is contained in:
Pedro Alves
2008-05-02 16:49:54 +00:00
parent 0428b8f567
commit 237fc4c9cd
16 changed files with 1257 additions and 34 deletions

View File

@@ -50,6 +50,7 @@ struct target_ops;
struct obstack;
struct bp_target_info;
struct target_desc;
struct displaced_step_closure;
extern struct gdbarch *current_gdbarch;
@@ -663,6 +664,95 @@ typedef void (gdbarch_skip_permanent_breakpoint_ftype) (struct regcache *regcach
extern void gdbarch_skip_permanent_breakpoint (struct gdbarch *gdbarch, struct regcache *regcache);
extern void set_gdbarch_skip_permanent_breakpoint (struct gdbarch *gdbarch, gdbarch_skip_permanent_breakpoint_ftype *skip_permanent_breakpoint);
/* The maximum length of an instruction on this architecture. */
extern int gdbarch_max_insn_length_p (struct gdbarch *gdbarch);
extern ULONGEST gdbarch_max_insn_length (struct gdbarch *gdbarch);
extern void set_gdbarch_max_insn_length (struct gdbarch *gdbarch, ULONGEST max_insn_length);
/* Copy the instruction at FROM to TO, and make any adjustments
necessary to single-step it at that address.
REGS holds the state the thread's registers will have before
executing the copied instruction; the PC in REGS will refer to FROM,
not the copy at TO. The caller should update it to point at TO later.
Return a pointer to data of the architecture's choice to be passed
to gdbarch_displaced_step_fixup. Or, return NULL to indicate that
the instruction's effects have been completely simulated, with the
resulting state written back to REGS.
For a general explanation of displaced stepping and how GDB uses it,
see the comments in infrun.c.
The TO area is only guaranteed to have space for
gdbarch_max_insn_length (arch) bytes, so this function must not
write more bytes than that to that area.
If you do not provide this function, GDB assumes that the
architecture does not support displaced stepping.
If your architecture doesn't need to adjust instructions before
single-stepping them, consider using simple_displaced_step_copy_insn
here. */
extern int gdbarch_displaced_step_copy_insn_p (struct gdbarch *gdbarch);
typedef struct displaced_step_closure * (gdbarch_displaced_step_copy_insn_ftype) (struct gdbarch *gdbarch, CORE_ADDR from, CORE_ADDR to, struct regcache *regs);
extern struct displaced_step_closure * gdbarch_displaced_step_copy_insn (struct gdbarch *gdbarch, CORE_ADDR from, CORE_ADDR to, struct regcache *regs);
extern void set_gdbarch_displaced_step_copy_insn (struct gdbarch *gdbarch, gdbarch_displaced_step_copy_insn_ftype *displaced_step_copy_insn);
/* Fix up the state resulting from successfully single-stepping a
displaced instruction, to give the result we would have gotten from
stepping the instruction in its original location.
REGS is the register state resulting from single-stepping the
displaced instruction.
CLOSURE is the result from the matching call to
gdbarch_displaced_step_copy_insn.
If you provide gdbarch_displaced_step_copy_insn.but not this
function, then GDB assumes that no fixup is needed after
single-stepping the instruction.
For a general explanation of displaced stepping and how GDB uses it,
see the comments in infrun.c. */
extern int gdbarch_displaced_step_fixup_p (struct gdbarch *gdbarch);
typedef void (gdbarch_displaced_step_fixup_ftype) (struct gdbarch *gdbarch, struct displaced_step_closure *closure, CORE_ADDR from, CORE_ADDR to, struct regcache *regs);
extern void gdbarch_displaced_step_fixup (struct gdbarch *gdbarch, struct displaced_step_closure *closure, CORE_ADDR from, CORE_ADDR to, struct regcache *regs);
extern void set_gdbarch_displaced_step_fixup (struct gdbarch *gdbarch, gdbarch_displaced_step_fixup_ftype *displaced_step_fixup);
/* Free a closure returned by gdbarch_displaced_step_copy_insn.
If you provide gdbarch_displaced_step_copy_insn, you must provide
this function as well.
If your architecture uses closures that don't need to be freed, then
you can use simple_displaced_step_free_closure here.
For a general explanation of displaced stepping and how GDB uses it,
see the comments in infrun.c. */
typedef void (gdbarch_displaced_step_free_closure_ftype) (struct gdbarch *gdbarch, struct displaced_step_closure *closure);
extern void gdbarch_displaced_step_free_closure (struct gdbarch *gdbarch, struct displaced_step_closure *closure);
extern void set_gdbarch_displaced_step_free_closure (struct gdbarch *gdbarch, gdbarch_displaced_step_free_closure_ftype *displaced_step_free_closure);
/* Return the address of an appropriate place to put displaced
instructions while we step over them. There need only be one such
place, since we're only stepping one thread over a breakpoint at a
time.
For a general explanation of displaced stepping and how GDB uses it,
see the comments in infrun.c. */
typedef CORE_ADDR (gdbarch_displaced_step_location_ftype) (struct gdbarch *gdbarch);
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);
/* Refresh overlay mapped state for section OSECT. */
extern int gdbarch_overlay_update_p (struct gdbarch *gdbarch);