record-full/record-btrace: software/hardware breakpoint trap

This adjusts the record targets to tell the core whether a trap was
caused by a breakpoint.  Targets that can do this should report
breakpoint traps with the PC already adjusted, so this removes the
re-incrementing record-full was doing.

These targets need to be adjusted before process_stratum targets
beneath are, otherwise target_supports_stopped_by_sw_breakpoint,
etc. would fall through to the target beneath while
recording/replaying, and the core would get confused.

Tested on x86-64 Fedora 20, native and gdbserver.

gdb/ChangeLog:
2015-03-04  Pedro Alves  <palves@redhat.com>

	* btrace.h: Include target/waitstatus.h.
	(struct btrace_thread_info) <stop_reason>: New field.
	* record-btrace.c (record_btrace_step_thread): Use
	record_check_stopped_by_breakpoint instead of breakpoint_here_p.
	(record_btrace_decr_pc_after_break): Delete.
	(record_btrace_stopped_by_sw_breakpoint)
	(record_btrace_supports_stopped_by_sw_breakpoint)
	(record_btrace_stopped_by_hw_breakpoint)
	(record_btrace_supports_stopped_by_hw_breakpoint): New functions.
	(init_record_btrace_ops): Install them.
	* record-full.c (record_full_hw_watchpoint): Delete and replace
	with ...
	(record_full_stop_reason): ... this throughout.
	(record_full_exec_insn): Adjust.
	(record_full_wait_1): Adjust.  No longer re-increment the PC.
	(record_full_wait_1): Adjust.  Use
	record_check_stopped_by_breakpoint instead of breakpoint_here_p.
	(record_full_stopped_by_watchpoint): Adjust.
	(record_full_stopped_by_sw_breakpoint)
	(record_full_supports_stopped_by_sw_breakpoint)
	(record_full_supports_stopped_by_sw_breakpoint)
	(record_full_stopped_by_hw_breakpoint)
	(record_full_supports_stopped_by_hw_breakpoint): New functions.
	(init_record_full_ops, init_record_full_core_ops): Install them.
	* record.c (record_check_stopped_by_breakpoint): New function.
	* record.h: Include target/waitstatus.h.
	(record_check_stopped_by_breakpoint): New declaration.
This commit is contained in:
Pedro Alves 2015-03-04 20:41:15 +00:00
parent 15c66dd626
commit 9e8915c6ce
6 changed files with 191 additions and 47 deletions

View file

@ -1,3 +1,33 @@
2015-03-04 Pedro Alves <palves@redhat.com>
* btrace.h: Include target/waitstatus.h.
(struct btrace_thread_info) <stop_reason>: New field.
* record-btrace.c (record_btrace_step_thread): Use
record_check_stopped_by_breakpoint instead of breakpoint_here_p.
(record_btrace_decr_pc_after_break): Delete.
(record_btrace_stopped_by_sw_breakpoint)
(record_btrace_supports_stopped_by_sw_breakpoint)
(record_btrace_stopped_by_hw_breakpoint)
(record_btrace_supports_stopped_by_hw_breakpoint): New functions.
(init_record_btrace_ops): Install them.
* record-full.c (record_full_hw_watchpoint): Delete and replace
with ...
(record_full_stop_reason): ... this throughout.
(record_full_exec_insn): Adjust.
(record_full_wait_1): Adjust. No longer re-increment the PC.
(record_full_wait_1): Adjust. Use
record_check_stopped_by_breakpoint instead of breakpoint_here_p.
(record_full_stopped_by_watchpoint): Adjust.
(record_full_stopped_by_sw_breakpoint)
(record_full_supports_stopped_by_sw_breakpoint)
(record_full_supports_stopped_by_sw_breakpoint)
(record_full_stopped_by_hw_breakpoint)
(record_full_supports_stopped_by_hw_breakpoint): New functions.
(init_record_full_ops, init_record_full_core_ops): Install them.
* record.c (record_check_stopped_by_breakpoint): New function.
* record.h: Include target/waitstatus.h.
(record_check_stopped_by_breakpoint): New declaration.
2015-03-04 Pedro Alves <palves@redhat.com>
enum lwp_stop_reason -> enum target_stop_reason

View file

@ -27,6 +27,7 @@
list of sequential control-flow blocks, one such list per thread. */
#include "btrace-common.h"
#include "target/waitstatus.h" /* For enum target_stop_reason. */
struct thread_info;
struct btrace_function;
@ -258,6 +259,9 @@ struct btrace_thread_info
Gaps are skipped during replay, so REPLAY always points to a valid
instruction. */
struct btrace_insn_iterator *replay;
/* Why the thread stopped, if we need to track it. */
enum target_stop_reason stop_reason;
};
/* Enable branch tracing for a thread. */

View file

@ -1954,7 +1954,8 @@ record_btrace_step_thread (struct thread_info *tp)
target_pid_to_str (tp->ptid),
core_addr_to_string_nz (insn->pc));
if (breakpoint_here_p (aspace, insn->pc))
if (record_check_stopped_by_breakpoint (aspace, insn->pc,
&btinfo->stop_reason))
return btrace_step_stopped ();
}
@ -1986,7 +1987,8 @@ record_btrace_step_thread (struct thread_info *tp)
target_pid_to_str (tp->ptid),
core_addr_to_string_nz (insn->pc));
if (breakpoint_here_p (aspace, insn->pc))
if (record_check_stopped_by_breakpoint (aspace, insn->pc,
&btinfo->stop_reason))
return btrace_step_stopped ();
}
}
@ -2044,18 +2046,58 @@ record_btrace_can_execute_reverse (struct target_ops *self)
return 1;
}
/* The to_decr_pc_after_break method of target record-btrace. */
/* The to_stopped_by_sw_breakpoint method of target record-btrace. */
static CORE_ADDR
record_btrace_decr_pc_after_break (struct target_ops *ops,
struct gdbarch *gdbarch)
static int
record_btrace_stopped_by_sw_breakpoint (struct target_ops *ops)
{
/* When replaying, we do not actually execute the breakpoint instruction
so there is no need to adjust the PC after hitting a breakpoint. */
if (record_btrace_is_replaying (ops))
return 0;
{
struct thread_info *tp = inferior_thread ();
return ops->beneath->to_decr_pc_after_break (ops->beneath, gdbarch);
return tp->btrace.stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
}
return ops->beneath->to_stopped_by_sw_breakpoint (ops->beneath);
}
/* The to_supports_stopped_by_sw_breakpoint method of target
record-btrace. */
static int
record_btrace_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
{
if (record_btrace_is_replaying (ops))
return 1;
return ops->beneath->to_supports_stopped_by_sw_breakpoint (ops->beneath);
}
/* The to_stopped_by_sw_breakpoint method of target record-btrace. */
static int
record_btrace_stopped_by_hw_breakpoint (struct target_ops *ops)
{
if (record_btrace_is_replaying (ops))
{
struct thread_info *tp = inferior_thread ();
return tp->btrace.stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
}
return ops->beneath->to_stopped_by_hw_breakpoint (ops->beneath);
}
/* The to_supports_stopped_by_hw_breakpoint method of target
record-btrace. */
static int
record_btrace_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
{
if (record_btrace_is_replaying (ops))
return 1;
return ops->beneath->to_supports_stopped_by_hw_breakpoint (ops->beneath);
}
/* The to_update_thread_list method of target record-btrace. */
@ -2238,7 +2280,12 @@ init_record_btrace_ops (void)
ops->to_goto_record_end = record_btrace_goto_end;
ops->to_goto_record = record_btrace_goto;
ops->to_can_execute_reverse = record_btrace_can_execute_reverse;
ops->to_decr_pc_after_break = record_btrace_decr_pc_after_break;
ops->to_stopped_by_sw_breakpoint = record_btrace_stopped_by_sw_breakpoint;
ops->to_supports_stopped_by_sw_breakpoint
= record_btrace_supports_stopped_by_sw_breakpoint;
ops->to_stopped_by_hw_breakpoint = record_btrace_stopped_by_hw_breakpoint;
ops->to_supports_stopped_by_hw_breakpoint
= record_btrace_supports_stopped_by_hw_breakpoint;
ops->to_execution_direction = record_btrace_execution_direction;
ops->to_prepare_to_generate_core = record_btrace_prepare_to_generate_core;
ops->to_done_generating_core = record_btrace_done_generating_core;

View file

@ -688,7 +688,8 @@ record_full_gdb_operation_disable_set (void)
}
/* Flag set to TRUE for target_stopped_by_watchpoint. */
static int record_full_hw_watchpoint = 0;
static enum target_stop_reason record_full_stop_reason
= TARGET_STOPPED_BY_NO_REASON;
/* Execute one instruction from the record log. Each instruction in
the log will be represented by an arbitrary sequence of register
@ -766,7 +767,7 @@ record_full_exec_insn (struct regcache *regcache,
if (hardware_watchpoint_inserted_in_range
(get_regcache_aspace (regcache),
entry->u.mem.addr, entry->u.mem.len))
record_full_hw_watchpoint = 1;
record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
}
}
}
@ -1079,6 +1080,8 @@ record_full_wait_1 (struct target_ops *ops,
record_full_get_sig = 0;
signal (SIGINT, record_full_sig_handler);
record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
if (!RECORD_FULL_IS_REPLAY && ops != &record_full_core_ops)
{
if (record_full_resume_step)
@ -1119,6 +1122,8 @@ record_full_wait_1 (struct target_ops *ops,
{
struct regcache *regcache;
struct address_space *aspace;
enum target_stop_reason *stop_reason_p
= &record_full_stop_reason;
/* Yes -- this is likely our single-step finishing,
but check if there's any reason the core would be
@ -1133,20 +1138,11 @@ record_full_wait_1 (struct target_ops *ops,
{
/* Always interested in watchpoints. */
}
else if (breakpoint_inserted_here_p (aspace, tmp_pc))
else if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
stop_reason_p))
{
/* There is a breakpoint here. Let the core
handle it. */
if (software_breakpoint_inserted_here_p (aspace, tmp_pc))
{
struct gdbarch *gdbarch
= get_regcache_arch (regcache);
CORE_ADDR decr_pc_after_break
= target_decr_pc_after_break (gdbarch);
if (decr_pc_after_break)
regcache_write_pc (regcache,
tmp_pc + decr_pc_after_break);
}
}
else
{
@ -1205,27 +1201,20 @@ record_full_wait_1 (struct target_ops *ops,
= make_cleanup (record_full_wait_cleanups, 0);
CORE_ADDR tmp_pc;
record_full_hw_watchpoint = 0;
record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON;
status->kind = TARGET_WAITKIND_STOPPED;
/* Check breakpoint when forward execute. */
if (execution_direction == EXEC_FORWARD)
{
tmp_pc = regcache_read_pc (regcache);
if (breakpoint_inserted_here_p (aspace, tmp_pc))
if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
&record_full_stop_reason))
{
int decr_pc_after_break = target_decr_pc_after_break (gdbarch);
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"Process record: break at %s.\n",
paddress (gdbarch, tmp_pc));
if (decr_pc_after_break
&& !record_full_resume_step
&& software_breakpoint_inserted_here_p (aspace, tmp_pc))
regcache_write_pc (regcache,
tmp_pc + decr_pc_after_break);
goto replay_out;
}
}
@ -1293,27 +1282,19 @@ record_full_wait_1 (struct target_ops *ops,
/* check breakpoint */
tmp_pc = regcache_read_pc (regcache);
if (breakpoint_inserted_here_p (aspace, tmp_pc))
if (record_check_stopped_by_breakpoint (aspace, tmp_pc,
&record_full_stop_reason))
{
int decr_pc_after_break
= target_decr_pc_after_break (gdbarch);
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
"Process record: break "
"at %s.\n",
paddress (gdbarch, tmp_pc));
if (decr_pc_after_break
&& execution_direction == EXEC_FORWARD
&& !record_full_resume_step
&& software_breakpoint_inserted_here_p (aspace,
tmp_pc))
regcache_write_pc (regcache,
tmp_pc + decr_pc_after_break);
continue_flag = 0;
}
if (record_full_hw_watchpoint)
if (record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
{
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
@ -1384,7 +1365,7 @@ static int
record_full_stopped_by_watchpoint (struct target_ops *ops)
{
if (RECORD_FULL_IS_REPLAY)
return record_full_hw_watchpoint;
return record_full_stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
else
return ops->beneath->to_stopped_by_watchpoint (ops->beneath);
}
@ -1398,6 +1379,40 @@ record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
return ops->beneath->to_stopped_data_address (ops->beneath, addr_p);
}
/* The to_stopped_by_sw_breakpoint method of target record-full. */
static int
record_full_stopped_by_sw_breakpoint (struct target_ops *ops)
{
return record_full_stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
}
/* The to_supports_stopped_by_sw_breakpoint method of target
record-full. */
static int
record_full_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
{
return 1;
}
/* The to_stopped_by_hw_breakpoint method of target record-full. */
static int
record_full_stopped_by_hw_breakpoint (struct target_ops *ops)
{
return record_full_stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
}
/* The to_supports_stopped_by_sw_breakpoint method of target
record-full. */
static int
record_full_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
{
return 1;
}
/* Record registers change (by user or by GDB) to list as an instruction. */
static void
@ -1926,6 +1941,14 @@ init_record_full_ops (void)
record_full_ops.to_remove_breakpoint = record_full_remove_breakpoint;
record_full_ops.to_stopped_by_watchpoint = record_full_stopped_by_watchpoint;
record_full_ops.to_stopped_data_address = record_full_stopped_data_address;
record_full_ops.to_stopped_by_sw_breakpoint
= record_full_stopped_by_sw_breakpoint;
record_full_ops.to_supports_stopped_by_sw_breakpoint
= record_full_supports_stopped_by_sw_breakpoint;
record_full_ops.to_stopped_by_hw_breakpoint
= record_full_stopped_by_hw_breakpoint;
record_full_ops.to_supports_stopped_by_hw_breakpoint
= record_full_supports_stopped_by_hw_breakpoint;
record_full_ops.to_can_execute_reverse = record_full_can_execute_reverse;
record_full_ops.to_stratum = record_stratum;
/* Add bookmark target methods. */
@ -2164,6 +2187,14 @@ init_record_full_core_ops (void)
= record_full_stopped_by_watchpoint;
record_full_core_ops.to_stopped_data_address
= record_full_stopped_data_address;
record_full_core_ops.to_stopped_by_sw_breakpoint
= record_full_stopped_by_sw_breakpoint;
record_full_core_ops.to_supports_stopped_by_sw_breakpoint
= record_full_supports_stopped_by_sw_breakpoint;
record_full_core_ops.to_stopped_by_hw_breakpoint
= record_full_stopped_by_hw_breakpoint;
record_full_core_ops.to_supports_stopped_by_hw_breakpoint
= record_full_supports_stopped_by_hw_breakpoint;
record_full_core_ops.to_can_execute_reverse
= record_full_can_execute_reverse;
record_full_core_ops.to_has_execution = record_full_core_has_execution;

View file

@ -189,6 +189,25 @@ record_kill (struct target_ops *t)
target_kill ();
}
/* See record.h. */
int
record_check_stopped_by_breakpoint (struct address_space *aspace, CORE_ADDR pc,
enum target_stop_reason *reason)
{
if (breakpoint_inserted_here_p (aspace, pc))
{
if (hardware_breakpoint_inserted_here_p (aspace, pc))
*reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
else
*reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
return 1;
}
*reason = TARGET_STOPPED_BY_NO_REASON;
return 0;
}
/* Implement "show record debug" command. */
static void

View file

@ -20,6 +20,8 @@
#ifndef _RECORD_H_
#define _RECORD_H_
#include "target/waitstatus.h" /* For enum target_stop_reason. */
struct cmd_list_element;
extern unsigned int record_debug;
@ -47,6 +49,17 @@ enum record_print_flag
RECORD_PRINT_INDENT_CALLS = (1 << 2)
};
/* Determined whether the target is stopped at a software or hardware
breakpoint, based on PC and the breakpoint tables. The breakpoint
type is translated to the appropriate target_stop_reason and
written to REASON. Returns true if stopped at a breakpoint, false
otherwise. */
extern int
record_check_stopped_by_breakpoint (struct address_space *aspace,
CORE_ADDR pc,
enum target_stop_reason *reason);
/* Wrapper for target_read_memory that prints a debug message if
reading memory fails. */
extern int record_read_memory (struct gdbarch *gdbarch,