summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2015-03-04 20:41:15 +0000
committerPedro Alves <palves@redhat.com>2015-03-04 20:41:15 +0000
commit9e8915c6cee5c37637521b424d723e990e06d597 (patch)
tree42ec607db6c86af4d136c70e2c588b5cd87bfbbd
parent15c66dd626380fbd7db6538b0c21d1fe86dda6c9 (diff)
downloadbinutils-gdb-9e8915c6cee5c37637521b424d723e990e06d597.tar.gz
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.
-rw-r--r--gdb/ChangeLog30
-rw-r--r--gdb/btrace.h4
-rw-r--r--gdb/record-btrace.c69
-rw-r--r--gdb/record-full.c103
-rw-r--r--gdb/record.c19
-rw-r--r--gdb/record.h13
6 files changed, 191 insertions, 47 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a1eab854147..11f6caa0b64 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,35 @@
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
* linux-nat.c (linux_resume_one_lwp, check_stopped_by_watchpoint)
(linux_nat_stopped_by_watchpoint, status_callback)
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 36bf5001f2c..b7437f173df 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -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. */
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index af7b65feda2..f2d35a3642e 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -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 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_decr_pc_after_break (ops->beneath, gdbarch);
+ 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;
diff --git a/gdb/record-full.c b/gdb/record-full.c
index c660743a407..0fbb2646e95 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -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;
diff --git a/gdb/record.c b/gdb/record.c
index 57851ecdfea..a64543aaae3 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -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
diff --git a/gdb/record.h b/gdb/record.h
index 771b14d99c0..101daae73ae 100644
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -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,