2000-04-30 Mark Kettenis <kettenis@gnu.org>
authorMark Kettenis <kettenis@gnu.org>
Sun, 30 Apr 2000 09:34:13 +0000 (09:34 +0000)
committerMark Kettenis <kettenis@gnu.org>
Sun, 30 Apr 2000 09:34:13 +0000 (09:34 +0000)
Fix single-stepping out of signal trampolines.
* config/i386/nm-linux.h (CHILD_RESUME): Define.
* i386-linux-nat.c (child_resume): New function.

gdb/ChangeLog
gdb/config/i386/nm-linux.h
gdb/i386-linux-nat.c

index ddbf754b3699c8d50cfd83cc358509a62a71a407..463d9c1f25a68bd6e07e251bd98bf6db3807969b 100644 (file)
@@ -1,3 +1,9 @@
+2000-04-30  Mark Kettenis  <kettenis@gnu.org>
+
+       Fix single-stepping out of signal trampolines.
+       * config/i386/nm-linux.h (CHILD_RESUME): Define.
+       * i386-linux-nat.c (child_resume): New function.
+
 Fri Apr 28 16:22:34 2000  Andrew Cagney  <cagney@b1.cygnus.com>
 
        * blockframe.c (frameless_look_for_prologue): Use
index 1095fa0db622a0c8b081b63d475b25d84a5275bb..4fb6965f4dde2dfc171a529062190df58145725f 100644 (file)
@@ -72,6 +72,9 @@ extern int kernel_u_size PARAMS ((void));
 #define CANNOT_FETCH_REGISTER(regno) ((regno) >= NUM_GREGS)
 #define CANNOT_STORE_REGISTER(regno) CANNOT_FETCH_REGISTER (regno)
 
+/* Override child_resume in `infptrace.c'.  */
+#define CHILD_RESUME
+
 extern CORE_ADDR
   i386_stopped_by_watchpoint PARAMS ((int));
 extern int
index 93ea241759f3df00dd9b2b22dd43a3b24c2aae4c..2bfac295efe35688effb8c27882224a3c164a534 100644 (file)
@@ -950,6 +950,91 @@ fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
     }
 }
 
+\f
+/* The instruction for a Linux system call is:
+       int $0x80
+   or 0xcd 0x80.  */
+
+static const unsigned char linux_syscall[] = { 0xcd, 0x80 };
+
+#define LINUX_SYSCALL_LEN (sizeof linux_syscall)
+
+/* The system call number is stored in the %eax register.  */
+#define LINUX_SYSCALL_REGNUM 0 /* %eax */
+
+/* We are specifically interested in the sigreturn and rt_sigreturn
+   system calls.  */
+
+#ifndef SYS_sigreturn
+#define SYS_sigreturn          0x77
+#endif
+#ifndef SYS_rt_sigreturn
+#define SYS_rt_sigreturn       0xad
+#endif
+
+/* Offset to saved processor flags, from <asm/sigcontext.h>.  */
+#define LINUX_SIGCONTEXT_EFLAGS_OFFSET (64)
+
+/* Resume execution of the inferior process.
+   If STEP is nonzero, single-step it.
+   If SIGNAL is nonzero, give it that signal.  */
+
+void
+child_resume (int pid, int step, enum target_signal signal)
+{
+  int request = PTRACE_CONT;
+
+  if (pid == -1)
+    /* Resume all threads.  */
+    /* I think this only gets used in the non-threaded case, where "resume
+       all threads" and "resume inferior_pid" are the same.  */
+    pid = inferior_pid;
+
+  if (step)
+    {
+      CORE_ADDR pc = read_pc_pid (pid);
+      unsigned char buf[LINUX_SYSCALL_LEN];
+
+      request = PTRACE_SINGLESTEP;
+
+      /* Returning from a signal trampoline is done by calling a
+         special system call (sigreturn or rt_sigreturn, see
+         i386-linux-tdep.c for more information).  This system call
+         restores the registers that were saved when the signal was
+         raised, including %eflags.  That means that single-stepping
+         won't work.  Instead, we'll have to modify the signal context
+         that's about to be restored, and set the trace flag there.  */
+
+      /* First check if PC is at a system call.  */
+      if (read_memory_nobpt (pc, (char *) buf, LINUX_SYSCALL_LEN) == 0
+         && memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0)
+       {
+         int syscall = read_register_pid (LINUX_SYSCALL_REGNUM, pid);
+
+         /* Then check the system call number.  */
+         if (syscall == SYS_sigreturn || syscall == SYS_rt_sigreturn)
+           {
+             CORE_ADDR sp = read_register (SP_REGNUM);
+             CORE_ADDR addr = sp;
+             unsigned long int eflags;
+             
+             if (syscall == SYS_rt_sigreturn)
+               addr = read_memory_integer (sp + 8, 4) + 20;
+
+             /* Set the trace flag in the context that's about to be
+                 restored.  */
+             addr += LINUX_SIGCONTEXT_EFLAGS_OFFSET;
+             read_memory (addr, (char *) &eflags, 4);
+             eflags |= 0x0100;
+             write_memory (addr, (char *) &eflags, 4);
+           }
+       }
+    }
+
+  if (ptrace (request, pid, 0, target_signal_to_host (signal)) == -1)
+    perror_with_name ("ptrace");
+}
+
 \f
 /* Calling functions in shared libraries.  */
 /* FIXME: kettenis/2000-03-05: Doesn't this belong in a
This page took 0.029117 seconds and 4 git commands to generate.