@@ -571,6 +571,14 @@ aarch64_supports_range_stepping (void)
return 1;
}
+/* Support for hardware single step. */
+
+static int
+aarch64_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
struct linux_target_ops the_low_target =
{
aarch64_arch_setup,
@@ -603,6 +611,7 @@ struct linux_target_ops the_low_target =
NULL, /* emit_ops */
NULL, /* get_min_fast_tracepoint_insn_len */
aarch64_supports_range_stepping,
+ aarch64_supports_hardware_single_step,
};
void
@@ -1112,6 +1112,14 @@ arm_arch_setup (void)
arm_set_byte_order ();
}
+/* Support for hardware single step. */
+
+static int
+arm_supports_hardware_single_step (void)
+{
+ return 0;
+}
+
/* Register sets without using PTRACE_GETREGSET. */
static struct regset_info arm_regsets[] = {
@@ -1190,6 +1198,7 @@ struct linux_target_ops the_low_target = {
NULL, /* emit_ops */
NULL, /* get_min_fast_tracepoint_insn_len */
NULL, /* supports_range_stepping */
+ arm_supports_hardware_single_step,
};
void
@@ -103,6 +103,14 @@ bfin_arch_setup (void)
current_process ()->tdesc = tdesc_bfin;
}
+/* Support for hardware single step. */
+
+static int
+bfin_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
static struct usrregs_info bfin_usrregs_info =
{
bfin_num_regs,
@@ -133,6 +141,26 @@ struct linux_target_ops the_low_target = {
NULL, /* get_next_pcs */
2,
bfin_breakpoint_at,
+ NULL, /* supports_z_point_type */
+ NULL, /* insert_point */
+ NULL, /* remove_point */
+ NULL, /* stopped_by_watchpoint */
+ NULL, /* stopped_data_address */
+ NULL, /* collect_ptrace_register */
+ NULL, /* supply_ptrace_register */
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ bfin_supports_hardware_single_step,
};
@@ -104,18 +104,6 @@ cris_breakpoint_at (CORE_ADDR where)
return 0;
}
-/* We only place breakpoints in empty marker functions, and thread locking
- is outside of the function. So rather than importing software single-step,
- we can just run until exit. */
-static void
-cris_get_next_pcs (struct get_next_pcs *next_pcs)
-{
- struct regcache *regcache = get_thread_regcache (current_thread, 1);
- CORE_ADDR pc;
- collect_register_by_name (regcache, "srp", &pc);
- VEC_safe_push (CORE_ADDR, next_pcs->result, pc);
-}
-
static void
cris_arch_setup (void)
{
@@ -149,13 +137,9 @@ struct linux_target_ops the_low_target = {
cris_get_pc,
cris_set_pc,
cris_breakpoint_from_pc,
- cris_get_next_pcs,
+ NULL,
0,
cris_breakpoint_at,
- 0,
- 0,
- 0,
- 0,
};
void
@@ -100,22 +100,6 @@ cris_breakpoint_at (CORE_ADDR where)
return 0;
}
-/* We only place breakpoints in empty marker functions, and thread locking
- is outside of the function. So rather than importing software single-step,
- we can just run until exit. */
-
-/* FIXME: This function should not be needed, since we have PTRACE_SINGLESTEP
- for CRISv32. Without it, td_ta_event_getmsg in thread_db_create_event
- will fail when debugging multi-threaded applications. */
-static void
-cris_get_next_pcs (struct get_next_pcs *next_pcs)
-{
- struct regcache *regcache = get_thread_regcache (current_thread, 1);
- CORE_ADDR pc;
- collect_register_by_name (regcache, "srp", &pc);
- VEC_safe_push (CORE_ADDR, next_pcs->result, pc);
-}
-
static void
cris_write_data_breakpoint (struct regcache *regcache,
int bp, unsigned long start, unsigned long end)
@@ -386,6 +370,14 @@ cris_arch_setup (void)
current_process ()->tdesc = tdesc_crisv32;
}
+/* Support for hardware single step. */
+
+static int
+cris_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
static struct regset_info cris_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, cris_num_regs * 4,
GENERAL_REGS, cris_fill_gregset, cris_store_gregset },
@@ -428,7 +420,7 @@ struct linux_target_ops the_low_target = {
cris_get_pc,
cris_set_pc,
cris_breakpoint_from_pc,
- cris_get_next_pcs,
+ NULL,
0,
cris_breakpoint_at,
cris_supports_z_point_type,
@@ -436,6 +428,21 @@ struct linux_target_ops the_low_target = {
cris_remove_point,
cris_stopped_by_watchpoint,
cris_stopped_data_address,
+ NULL, /* collect_ptrace_register */
+ NULL, /* supply_ptrace_register */
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ cris_supports_hardware_single_step,
};
void
@@ -272,22 +272,35 @@ static void complete_ongoing_step_over (void);
being stepped. */
ptid_t step_over_bkpt;
-/* True if the low target can hardware single-step. Such targets
- don't need a GET_NEXT_PCS callback. */
+/* True if the low target can hardware single-step. */
static int
can_hardware_single_step (void)
{
- return (the_low_target.get_next_pcs == NULL);
+ if (the_low_target.supports_hardware_single_step != NULL)
+ return the_low_target.supports_hardware_single_step ();
+ else
+ return 0;
+}
+
+/* True if the low target can software single-step. Such targets
+ implement the GET_NEXT_PCS callback. */
+
+static int
+can_software_single_step (void)
+{
+ return (the_low_target.get_next_pcs != NULL);
}
-/* True if the low target supports memory breakpoints. If so, we'll
- have a GET_PC implementation. */
+/* True if the low target supports memory breakpoints. If so, we'll have a
+ GET_PC implementation. We will also need to support hardware or software
+ single stepping. */
static int
supports_breakpoints (void)
{
- return (the_low_target.get_pc != NULL);
+ return (the_low_target.get_pc != NULL &&
+ (can_hardware_single_step () || can_software_single_step ()));
}
/* Returns true if this target can support fast tracepoints. This
@@ -4026,10 +4039,16 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp,
{
step = 1;
}
- else {
- install_software_single_step_breakpoints (lwp);
- step = 0;
- }
+ else if (can_software_single_step ())
+ {
+ install_software_single_step_breakpoints (lwp);
+ step = 0;
+ }
+ else
+ {
+ internal_error (__FILE__, __LINE__,
+ "stepping is not implemented on this target");
+ }
}
if (proc->tdesc != NULL && the_low_target.get_pc != NULL)
@@ -4439,11 +4458,16 @@ start_step_over (struct lwp_info *lwp)
{
step = 1;
}
- else
+ else if (can_software_single_step ())
{
install_software_single_step_breakpoints (lwp);
step = 0;
}
+ else
+ {
+ internal_error (__FILE__, __LINE__,
+ "stepping is not implemented on this target");
+ }
current_thread = saved_thread;
@@ -5638,6 +5662,12 @@ linux_supports_hardware_single_step (void)
}
static int
+linux_supports_software_single_step (void)
+{
+ return can_software_single_step ();
+}
+
+static int
linux_stopped_by_watchpoint (void)
{
struct lwp_info *lwp = get_thread_lwp (current_thread);
@@ -7064,6 +7094,7 @@ static struct target_ops linux_target_ops = {
linux_mntns_unlink,
linux_mntns_readlink,
linux_breakpoint_from_pc,
+ linux_supports_software_single_step,
};
static void
@@ -240,6 +240,9 @@ struct linux_target_ops
/* Returns true if the low target supports range stepping. */
int (*supports_range_stepping) (void);
+
+ /* Returns true if the low target supports hardware single step. */
+ int (*supports_hardware_single_step) (void);
};
extern struct linux_target_ops the_low_target;
@@ -101,6 +101,14 @@ m32r_arch_setup (void)
current_process ()->tdesc = tdesc_m32r;
}
+/* Support for hardware single step. */
+
+static int
+m32r_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
static struct usrregs_info m32r_usrregs_info =
{
m32r_num_regs,
@@ -131,6 +139,26 @@ struct linux_target_ops the_low_target = {
NULL,
0,
m32r_breakpoint_at,
+ NULL, /* supports_z_point_type */
+ NULL, /* insert_point */
+ NULL, /* remove_point */
+ NULL, /* stopped_by_watchpoint */
+ NULL, /* stopped_data_address */
+ NULL, /* collect_ptrace_register */
+ NULL, /* supply_ptrace_register */
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ m32r_supports_hardware_single_step,
};
void
@@ -274,21 +274,6 @@ mips_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
return (const unsigned char *) &mips_breakpoint;
}
-/* We only place breakpoints in empty marker functions, and thread locking
- is outside of the function. So rather than importing software single-step,
- we can just run until exit. */
-static void
-mips_get_next_pcs (struct get_next_pcs *next_pcs)
-{
- CORE_ADDR result;
- struct regcache *regcache = get_thread_regcache (current_thread, 1);
- union mips_register ra;
- collect_register_by_name (regcache, "r31", ra.buf);
- result = register_size (regcache->tdesc, 0) == 4 ? ra.reg32 : ra.reg64;
-
- VEC_safe_push (CORE_ADDR, next_pcs->result, result);
-}
-
static int
mips_breakpoint_at (CORE_ADDR where)
{
@@ -893,7 +878,7 @@ struct linux_target_ops the_low_target = {
mips_get_pc,
mips_set_pc,
mips_breakpoint_from_pc,
- mips_get_next_pcs,
+ NULL, /* get_next_pcs */
0,
mips_breakpoint_at,
mips_supports_z_point_type,
@@ -146,18 +146,6 @@ nios2_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
return (const unsigned char *) &nios2_breakpoint;
}
-/* Implement the get_next_pcs linux_target_ops method. */
-
-static void
-nios2_get_next_pcs (struct get_next_pcs *next_pcs)
-{
- union nios2_register ra;
- struct regcache *regcache = get_thread_regcache (current_thread, 1);
-
- collect_register_by_name (regcache, "ra", ra.buf);
- VEC_safe_push (CORE_ADDR, next_pcs->result, ra.reg32);
-}
-
/* Implement the breakpoint_at linux_target_ops method. */
static int
@@ -280,7 +268,7 @@ struct linux_target_ops the_low_target =
nios2_get_pc,
nios2_set_pc,
nios2_breakpoint_from_pc,
- nios2_get_next_pcs,
+ NULL, /* get_next_pcs */
0,
nios2_breakpoint_at,
};
@@ -641,6 +641,14 @@ ppc_store_evrregset (struct regcache *regcache, const void *buf)
supply_register_by_name (regcache, "spefscr", ®set->spefscr);
}
+/* Support for hardware single step. */
+
+static int
+ppc_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
static struct regset_info ppc_regsets[] = {
/* List the extra register sets before GENERAL_REGS. That way we will
fetch them every time, but still fall back to PTRACE_PEEKUSER for the
@@ -701,6 +709,19 @@ struct linux_target_ops the_low_target = {
NULL,
ppc_collect_ptrace_register,
ppc_supply_ptrace_register,
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ ppc_supports_hardware_single_step,
};
void
@@ -611,6 +611,14 @@ s390_breakpoint_at (CORE_ADDR pc)
return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0;
}
+/* Support for hardware single step. */
+
+static int
+s390_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
static struct usrregs_info s390_usrregs_info =
{
s390_num_regs,
@@ -687,6 +695,19 @@ struct linux_target_ops the_low_target = {
NULL,
s390_collect_ptrace_register,
s390_supply_ptrace_register,
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ s390_supports_hardware_single_step,
};
void
@@ -98,6 +98,14 @@ sh_breakpoint_at (CORE_ADDR where)
return 0;
}
+/* Support for hardware single step. */
+
+static int
+sh_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
/* Provide only a fill function for the general register set. ps_lgetregs
will use this for NPTL support. */
@@ -159,6 +167,26 @@ struct linux_target_ops the_low_target = {
NULL,
0,
sh_breakpoint_at,
+ NULL, /* supports_z_point_type */
+ NULL, /* insert_point */
+ NULL, /* remove_point */
+ NULL, /* stopped_by_watchpoint */
+ NULL, /* stopped_data_address */
+ NULL, /* collect_ptrace_register */
+ NULL, /* supply_ptrace_register */
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ sh_supports_hardware_single_step,
};
void
@@ -264,19 +264,6 @@ sparc_breakpoint_at (CORE_ADDR where)
return 0;
}
-/* We only place breakpoints in empty marker functions, and thread locking
- is outside of the function. So rather than importing software single-step,
- we can just run until exit. */
-static void
-sparc_get_next_pcs (struct get_next_pcs *next_pcs)
-{
- struct regcache *regcache = get_thread_regcache (current_thread, 1);
- CORE_ADDR lr;
- /* O7 is the equivalent to the 'lr' of other archs. */
- collect_register_by_name (regcache, "o7", &lr);
- VEC_safe_push (CORE_ADDR, next_pcs->result, lr);
-}
-
static void
sparc_arch_setup (void)
{
@@ -331,7 +318,7 @@ struct linux_target_ops the_low_target = {
/* No sparc_set_pc is needed. */
NULL,
sparc_breakpoint_from_pc,
- sparc_get_next_pcs,
+ NULL,
0,
sparc_breakpoint_at,
NULL, /* supports_z_point_type */
@@ -339,6 +339,14 @@ tic6x_arch_setup (void)
current_process ()->tdesc = tic6x_read_description ();
}
+/* Support for hardware single step. */
+
+static int
+tic6x_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
static struct regsets_info tic6x_regsets_info =
{
tic6x_regsets, /* regsets */
@@ -377,6 +385,26 @@ struct linux_target_ops the_low_target = {
NULL,
0,
tic6x_breakpoint_at,
+ NULL, /* supports_z_point_type */
+ NULL, /* insert_point */
+ NULL, /* remove_point */
+ NULL, /* stopped_by_watchpoint */
+ NULL, /* stopped_data_address */
+ NULL, /* collect_ptrace_register */
+ NULL, /* supply_ptrace_register */
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ tic6x_supports_hardware_single_step,
};
void
@@ -179,6 +179,14 @@ tile_arch_setup (void)
current_process ()->tdesc = tdesc_tilegx;
}
+/* Support for hardware single step. */
+
+static int
+tile_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
struct linux_target_ops the_low_target =
{
@@ -190,9 +198,29 @@ struct linux_target_ops the_low_target =
tile_get_pc,
tile_set_pc,
tile_breakpoint_from_pc,
- NULL,
+ NULL, /* get_next_pcs */
0,
tile_breakpoint_at,
+ NULL, /* supports_z_point_type */
+ NULL, /* insert_point */
+ NULL, /* remove_point */
+ NULL, /* stopped_by_watchpoint */
+ NULL, /* stopped_data_address */
+ NULL, /* collect_ptrace_register */
+ NULL, /* supply_ptrace_register */
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ tile_supports_hardware_single_step,
};
void
@@ -3256,6 +3256,14 @@ x86_supports_range_stepping (void)
return 1;
}
+/* Support for hardware single step. */
+
+static int
+x86_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
/* This is initialized assuming an amd64 target.
x86_arch_setup will correct it for i386 or amd64 targets. */
@@ -3295,6 +3303,7 @@ struct linux_target_ops the_low_target =
x86_emit_ops,
x86_get_min_fast_tracepoint_insn_len,
x86_supports_range_stepping,
+ x86_supports_hardware_single_step,
};
void
@@ -227,6 +227,14 @@ xtensa_arch_setup (void)
current_process ()->tdesc = tdesc_xtensa;
}
+/* Support for hardware single step. */
+
+static int
+xtensa_supports_hardware_single_step (void)
+{
+ return 1;
+}
+
static const struct regs_info *
xtensa_regs_info (void)
{
@@ -245,6 +253,26 @@ struct linux_target_ops the_low_target = {
NULL,
0,
xtensa_breakpoint_at,
+ NULL, /* supports_z_point_type */
+ NULL, /* insert_point */
+ NULL, /* remove_point */
+ NULL, /* stopped_by_watchpoint */
+ NULL, /* stopped_data_address */
+ NULL, /* collect_ptrace_register */
+ NULL, /* supply_ptrace_register */
+ NULL, /* siginfo_fixup */
+ NULL, /* new_process */
+ NULL, /* new_thread */
+ NULL, /* new_fork */
+ NULL, /* prepare_to_resume */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* get_thread_area */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* supports_range_stepping */
+ xtensa_supports_hardware_single_step,
};
@@ -2192,13 +2192,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
strcat (own_buf, ";tracenz+");
}
- if (target_supports_hardware_single_step ())
+ if (target_supports_hardware_single_step () ||
+ target_supports_software_single_step () )
{
- /* Support target-side breakpoint conditions and commands.
- GDBserver needs to step over the breakpoint if the condition
- is false. GDBserver software single step is too simple, so
- disable conditional breakpoints if the target doesn't have
- hardware single step. */
strcat (own_buf, ";ConditionalBreakpoints+");
}
strcat (own_buf, ";BreakpointCommands+");
@@ -224,3 +224,10 @@ target_can_do_hardware_single_step (void)
{
return 1;
}
+
+/* Target can do software single step. */
+int
+target_can_do_software_single_step (void)
+{
+ return 0;
+}
@@ -443,6 +443,9 @@ struct target_ops
can be NULL, the default breakpoint for the target should be returned in
this case. */
const unsigned char *(*breakpoint_from_pc) (CORE_ADDR *pcptr, int *lenptr);
+
+ /* Returns true if the target can do software single step. */
+ int (*supports_software_single_step) (void);
};
extern struct target_ops *the_target;
@@ -621,6 +624,10 @@ int kill_inferior (int);
(the_target->stopped_by_hw_breakpoint ? \
(*the_target->stopped_by_hw_breakpoint) () : 0)
+#define target_supports_software_single_step() \
+ (the_target->supports_software_single_step ? \
+ (*the_target->supports_software_single_step) () : 0)
+
/* Start non-stop mode, returns 0 on success, -1 on failure. */
int start_non_stop (int nonstop);
@@ -655,4 +662,6 @@ const char *target_pid_to_str (ptid_t);
int target_can_do_hardware_single_step (void);
+int target_can_do_software_single_step (void);
+
#endif /* TARGET_H */