2009-09-21 Hui Zhu <teawater@gmail.com>
authorHui Zhu <teawater@gmail.com>
Mon, 21 Sep 2009 05:54:09 +0000 (05:54 +0000)
committerHui Zhu <teawater@gmail.com>
Mon, 21 Sep 2009 05:54:09 +0000 (05:54 +0000)
    Michael Snyder  <msnyder@vmware.com>

* record.c (record_end_entry): New struct.
(record_type): Add end.
(record_arch_list_add_end): Set rec->u.end.sigval to
TARGET_SIGNAL_0.
(record_message_args): New struct.
(record_message): Call gdbarch_process_record_signal.
(do_record_message): Add argument "signal".
(record_resume): Ditto.
(record_wait): Ditto.  Check record_list->u.end.sigval
in replay mode.

gdb/ChangeLog
gdb/record.c

index 6cf888912d17c7cf4e643e1790539de168af8d17..2558705b396fd20680fd4e9a2d5e78eb7ece5bef 100644 (file)
@@ -1,3 +1,17 @@
+2009-09-21  Hui Zhu  <teawater@gmail.com>
+           Michael Snyder  <msnyder@vmware.com>
+
+       * record.c (record_end_entry): New struct.
+       (record_type): Add end.
+       (record_arch_list_add_end): Set rec->u.end.sigval to
+       TARGET_SIGNAL_0.
+       (record_message_args): New struct.
+       (record_message): Call gdbarch_process_record_signal.
+       (do_record_message): Add argument "signal".
+       (record_resume): Ditto.
+       (record_wait): Ditto.  Check record_list->u.end.sigval
+       in replay mode.
+
 2009-09-21  Hui Zhu  <teawater@gmail.com>
            Michael Snyder  <msnyder@vmware.com>
 
index fbf00031db37ce3a34dc3a4a6c76ddbc79fd7911..8ad5bf8c74295a632886e10b4f129cf598b4f3e5 100644 (file)
@@ -59,6 +59,11 @@ struct record_mem_entry
   gdb_byte *val;
 };
 
+struct record_end_entry
+{
+  enum target_signal sigval;
+};
+
 enum record_type
 {
   record_end = 0,
@@ -77,6 +82,8 @@ struct record_entry
     struct record_reg_entry reg;
     /* mem */
     struct record_mem_entry mem;
+    /* end */
+    struct record_end_entry end;
   } u;
 };
 
@@ -314,6 +321,7 @@ record_arch_list_add_end (void)
   rec->prev = NULL;
   rec->next = NULL;
   rec->type = record_end;
+  rec->u.end.sigval = TARGET_SIGNAL_0;
 
   record_arch_list_add (rec);
 
@@ -360,11 +368,17 @@ record_message_cleanups (void *ignore)
   record_list_release (record_arch_list_tail);
 }
 
+struct record_message_args {
+  struct regcache *regcache;
+  enum target_signal signal;
+};
+
 static int
 record_message (void *args)
 {
   int ret;
-  struct regcache *regcache = args;
+  struct record_message_args *myargs = args;
+  struct gdbarch *gdbarch = get_regcache_arch (myargs->regcache);
   struct cleanup *old_cleanups = make_cleanup (record_message_cleanups, 0);
 
   record_arch_list_head = NULL;
@@ -373,9 +387,44 @@ record_message (void *args)
   /* Check record_insn_num.  */
   record_check_insn_num (1);
 
-  ret = gdbarch_process_record (get_regcache_arch (regcache),
-                               regcache,
-                               regcache_read_pc (regcache));
+  /* If gdb sends a signal value to target_resume,
+     save it in the 'end' field of the previous instruction.
+
+     Maybe process record should record what really happened,
+     rather than what gdb pretends has happened.
+
+     So if Linux delivered the signal to the child process during
+     the record mode, we will record it and deliver it again in
+     the replay mode.
+
+     If user says "ignore this signal" during the record mode, then
+     it will be ignored again during the replay mode (no matter if
+     the user says something different, like "deliver this signal"
+     during the replay mode).
+
+     User should understand that nothing he does during the replay
+     mode will change the behavior of the child.  If he tries,
+     then that is a user error.
+
+     But we should still deliver the signal to gdb during the replay,
+     if we delivered it during the recording.  Therefore we should
+     record the signal during record_wait, not record_resume.  */
+  if (record_list != &record_first)    /* FIXME better way to check */
+    {
+      gdb_assert (record_list->type == record_end);
+      record_list->u.end.sigval = myargs->signal;
+    }
+
+  if (myargs->signal == TARGET_SIGNAL_0
+      || !gdbarch_process_record_signal_p (gdbarch))
+    ret = gdbarch_process_record (gdbarch,
+                                 myargs->regcache,
+                                 regcache_read_pc (myargs->regcache));
+  else
+    ret = gdbarch_process_record_signal (gdbarch,
+                                        myargs->regcache,
+                                        myargs->signal);
+
   if (ret > 0)
     error (_("Process record: inferior program stopped."));
   if (ret < 0)
@@ -396,9 +445,14 @@ record_message (void *args)
 }
 
 static int
-do_record_message (struct regcache *regcache)
+do_record_message (struct regcache *regcache,
+                  enum target_signal signal)
 {
-  return catch_errors (record_message, regcache, NULL, RETURN_MASK_ALL);
+  struct record_message_args args;
+
+  args.regcache = regcache;
+  args.signal = signal;
+  return catch_errors (record_message, &args, NULL, RETURN_MASK_ALL);
 }
 
 /* Set to 1 if record_store_registers and record_xfer_partial
@@ -520,13 +574,13 @@ static int record_resume_error;
 
 static void
 record_resume (struct target_ops *ops, ptid_t ptid, int step,
-               enum target_signal siggnal)
+               enum target_signal signal)
 {
   record_resume_step = step;
 
   if (!RECORD_IS_REPLAY)
     {
-      if (do_record_message (get_current_regcache ()))
+      if (do_record_message (get_current_regcache (), signal))
         {
           record_resume_error = 0;
         }
@@ -536,7 +590,7 @@ record_resume (struct target_ops *ops, ptid_t ptid, int step,
           return;
         }
       record_beneath_to_resume (record_beneath_to_resume_ops, ptid, 1,
-                                siggnal);
+                                signal);
     }
 }
 
@@ -611,15 +665,16 @@ record_wait (struct target_ops *ops,
              ret = record_beneath_to_wait (record_beneath_to_wait_ops,
                                            ptid, status, options);
 
+             /* Is this a SIGTRAP?  */
              if (status->kind == TARGET_WAITKIND_STOPPED
                  && status->value.sig == TARGET_SIGNAL_TRAP)
                {
-                 /* Check if there is a breakpoint.  */
+                 /* Yes -- check if there is a breakpoint.  */
                  registers_changed ();
                  tmp_pc = regcache_read_pc (get_current_regcache ());
                  if (breakpoint_inserted_here_p (tmp_pc))
                    {
-                     /* There is a breakpoint.  */
+                     /* There is a breakpoint.  GDB will want to stop.  */
                      CORE_ADDR decr_pc_after_break =
                        gdbarch_decr_pc_after_break
                        (get_regcache_arch (get_current_regcache ()));
@@ -631,8 +686,12 @@ record_wait (struct target_ops *ops,
                    }
                  else
                    {
-                     /* There is not a breakpoint.  */
-                     if (!do_record_message (get_current_regcache ()))
+                     /* There is not a breakpoint, and gdb is not
+                        stepping, therefore gdb will not stop.
+                        Therefore we will not return to gdb.
+                        Record the insn and resume.  */
+                     if (!do_record_message (get_current_regcache (),
+                                             TARGET_SIGNAL_0))
                        {
                           break;
                        }
@@ -827,6 +886,10 @@ record_wait (struct target_ops *ops,
                                           gdbarch_decr_pc_after_break (gdbarch));
                      continue_flag = 0;
                    }
+                 /* Check target signal */
+                 if (record_list->u.end.sigval != TARGET_SIGNAL_0)
+                   /* FIXME: better way to check */
+                   continue_flag = 0;
                }
            }
 
@@ -851,6 +914,9 @@ record_wait (struct target_ops *ops,
 replay_out:
       if (record_get_sig)
        status->value.sig = TARGET_SIGNAL_INT;
+      else if (record_list->u.end.sigval != TARGET_SIGNAL_0)
+       /* FIXME: better way to check */
+       status->value.sig = record_list->u.end.sigval;
       else
        status->value.sig = TARGET_SIGNAL_TRAP;