This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 3/8] 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-02-25  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.
---
 gdb/btrace.h        |   4 ++
 gdb/record-btrace.c |  69 +++++++++++++++++++++++++++++------
 gdb/record-full.c   | 103 ++++++++++++++++++++++++++++++++++------------------
 gdb/record.c        |  19 ++++++++++
 gdb/record.h        |  13 +++++++
 5 files changed, 161 insertions(+), 47 deletions(-)

diff --git a/gdb/btrace.h b/gdb/btrace.h
index 0ddd4c1..a17b3cb 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;
@@ -261,6 +262,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 102e0eb..ef5f367 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1919,7 +1919,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 ();
 	}
 
@@ -1951,7 +1952,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 ();
 	}
     }
@@ -2009,18 +2011,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.  */
@@ -2203,7 +2245,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 c660743..0fbb264 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 57851ec..a64543a 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 771b14d..101daae 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,
-- 
1.9.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]