Blob Blame History Raw
for gdb-6.3/gdb/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* i386-linux-nat.c (i386_debug_register_for_thread): New struct.
	(i386_linux_set_dr_for_thread): Rename from...
	(i386_linux_set_debug_regs_for_thread): ... this, and
	add new function to catch exceptions in the old one.

2008-02-24  Jan Kratochvil  <jan.kratochvil@redhat.com>

	Port to GDB-6.8pre.

This patch was originally made to workaround a deficiency of ia32el (==ia32
emulator on ia64) which EIOs on ptrace(2) of the debug registers.

Currently I can no longer run gdb.i386 on RHEL-5.1.ia64 as it fails on
	$ rpm -qv kernel
	kernel-2.6.18-53.el5.ia64
	$ file /emul/ia32-linux/usr/bin/gdb ./print-threads
	/emul/ia32-linux/usr/bin/gdb: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped
	./print-threads:              ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped
	$ /emul/ia32-linux/usr/bin/gdb ./print-threads
	(gdb) r
	Starting program: /root/jkratoch/redhat/print-threads 
	Warning:
	Cannot insert breakpoint -2.
	Error accessing memory address 0x555766fb: Input/output error.
	(gdb) maint info breakpoints 
	Num Type           Disp Enb Address    What
	-1  longjmp resume keep n   0x00000000 
	-2  shlib events   keep y   0x555766fb 

ia32-on-ia64 run problem info:

the inconsistency is in function linux_nat_wait - there is a variable called
block_mask, which is assumed to represent the current signal mask. in the
following execution path this assumption does not hold:

1) block-mask is filled with SIGCHLD and the signal is masked in
   lin_lwp_attach_lwp, which is called at the beginning of the procedure
   that handles a new thread in the debuggee.
2) further down this procedure gdb tries to set the debug regs of the debuggee.
   when trying to set debug regs - gdb fails and calls throw_exception. this
   function finishes with siglongjmp, which clears the sigmask (seq. 1).
3) further down, linux_nat_wait is called to wait on the new child. in
   linux_nat_wait there is a sequence :

      if ( ! (block_mask & SIGCHLD) )
        mask- SIGCHLD
        while () {
          wait-no-hang( )
          if no child found then
            sigsuspend (SIGCHLD)

4) the signal that notifies the debugger about the child is received after the
   wait and before the sigsuspend. originally, this was not supposed to happen
   because SIGCHLD is supposed to be blocked, but because what happens in step
   2, the signal mask is cleared and the signal is received at this point,
   which results with a hang

sequence 1:

catch_errors (symbol_add_stubs)
  symbol_file_add_with_addrs_or_offsets
    deprecated_target_new_objfile_hook
      tui_new_objfile_hook
        attach_thread
          observer_notify_linux_new_thread
            generic_observer_notify
              observer_linux_new_thread_notification_stub
                i386_linux_new_thread
                  i386_linux_set_debug_regs_for_thread
                    i386_linux_dr_set_addr
                      i386_linux_dr_set
                        perror_with_name
                          .
                          .
                          .
                          throw_exception
                            siglongjmp

RHEL Bug 175270

Index: gdb-6.8cvs20080219/gdb/i386-linux-nat.c
===================================================================
--- gdb-6.8cvs20080219.orig/gdb/i386-linux-nat.c	2008-01-10 19:19:02.000000000 +0100
+++ gdb-6.8cvs20080219/gdb/i386-linux-nat.c	2008-02-24 09:23:09.000000000 +0100
@@ -24,6 +24,7 @@
 #include "regcache.h"
 #include "target.h"
 #include "linux-nat.h"
+#include "exceptions.h"
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
@@ -611,20 +612,40 @@ i386_linux_dr_get (ptid_t ptid, int regn
   return value;
 }
 
-static void
-i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
-{
-  int tid;
+struct i386_linux_dr_set
+  {
+    int tid;
+    int regnum;
+    unsigned long value;
+  };
 
-  tid = TIDGET (ptid);
-  if (tid == 0)
-    tid = PIDGET (ptid);
+static int
+i386_linux_dr_set_core (void *data_pointer)
+{
+  struct i386_linux_dr_set *data = data_pointer;
 
   errno = 0;
-  ptrace (PTRACE_POKEUSER, tid,
-	  offsetof (struct user, u_debugreg[regnum]), value);
+  ptrace (PTRACE_POKEUSER, data->tid,
+	  offsetof (struct user, u_debugreg[data->regnum]), data->value);
   if (errno != 0)
     perror_with_name (_("Couldn't write debug register"));
+  return 1;
+}
+
+static int
+i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
+{
+  struct i386_linux_dr_set data;
+  int tid;
+
+  data.tid = TIDGET (ptid);
+  if (data.tid == 0)
+    data.tid = PIDGET (ptid);
+
+  data.regnum = regnum;
+  data.value = value;
+
+  return catch_errors (i386_linux_dr_set_core, &data, "", RETURN_MASK_ALL);
 }
 
 void
Index: gdb-6.8cvs20080219/gdb/Makefile.in
===================================================================
--- gdb-6.8cvs20080219.orig/gdb/Makefile.in	2008-02-24 09:13:35.000000000 +0100
+++ gdb-6.8cvs20080219/gdb/Makefile.in	2008-02-24 09:14:26.000000000 +0100
@@ -2252,7 +2252,7 @@ i386gnu-tdep.o: i386gnu-tdep.c $(defs_h)
 i386-linux-nat.o: i386-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
 	$(regcache_h) $(linux_nat_h) $(gdb_assert_h) $(gdb_string_h) \
 	$(gregset_h) $(i387_tdep_h) $(i386_tdep_h) $(i386_linux_tdep_h) \
-	$(gdb_proc_service_h) $(target_h)
+	$(gdb_proc_service_h) $(target_h) $(exceptions_h)
 i386-linux-tdep.o: i386-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) \
 	$(value_h) $(regcache_h) $(inferior_h) $(osabi_h) $(reggroups_h) \
 	$(dwarf2_frame_h) $(gdb_string_h) $(i386_tdep_h) \