static void inf_ptrace_resume (struct target_ops *ops, ptid_t ptid, int step, enum gdb_signal signal) { pid_t pid = ptid_get_pid (ptid); int request; if (pid == -1) /* Resume all threads. Traditionally ptrace() only supports single-threaded processes, so simply resume the inferior. */ pid = ptid_get_pid (inferior_ptid); if (catch_syscall_enabled () > 0) request = PT_SYSCALL; else request = PT_CONTINUE; if (step) { /* If this system does not support PT_STEP, a higher level function will have called single_step() to transmute the step request into a continue request (by setting breakpoints on all possible successor instructions), so we don't have to worry about that here. */ request = PT_STEP; } /* An address of (PTRACE_TYPE_ARG3)1 tells ptrace to continue from where it was. If GDB wanted it to start some other way, we have already written a new program counter value to the child. */ errno = 0; ptrace (request, pid, (PTRACE_TYPE_ARG3)1, gdb_signal_to_host (signal)); if (errno != 0) perror_with_name (("ptrace")); }
static void i386fbsd_resume (struct target_ops *ops, ptid_t ptid, int step, enum gdb_signal signal) { pid_t pid = ptid_get_pid (ptid); int request = PT_STEP; if (pid == -1) /* Resume all threads. This only gets used in the non-threaded case, where "resume all threads" and "resume inferior_ptid" are the same. */ pid = ptid_get_pid (inferior_ptid); if (!step) { struct regcache *regcache = get_current_regcache (); ULONGEST eflags; /* Workaround for a bug in FreeBSD. Make sure that the trace flag is off when doing a continue. There is a code path through the kernel which leaves the flag set when it should have been cleared. If a process has a signal pending (such as SIGALRM) and we do a PT_STEP, the process never really has a chance to run because the kernel needs to notify the debugger that a signal is being sent. Therefore, the process never goes through the kernel's trap() function which would normally clear it. */ regcache_cooked_read_unsigned (regcache, I386_EFLAGS_REGNUM, &eflags); if (eflags & 0x0100) regcache_cooked_write_unsigned (regcache, I386_EFLAGS_REGNUM, eflags & ~0x0100); request = PT_CONTINUE; } /* An addres of (caddr_t) 1 tells ptrace to continue from where it was. (If GDB wanted it to start some other way, we have already written a new PC value to the child.) */ if (ptrace (request, pid, (caddr_t) 1, gdb_signal_to_host (signal)) == -1) perror_with_name (("ptrace")); }
ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, int connected_wait) { ptid_t ret; if (connected_wait) server_waiting = 1; ret = (*the_target->wait) (ptid, ourstatus, options); /* We don't expose _LOADED events to gdbserver core. See the `dlls_changed' global. */ if (ourstatus->kind == TARGET_WAITKIND_LOADED) ourstatus->kind = TARGET_WAITKIND_STOPPED; /* If GDB is connected through TCP/serial, then GDBserver will most probably be running on its own terminal/console, so it's nice to print there why is GDBserver exiting. If however, GDB is connected through stdio, then there's no need to spam the GDB console with this -- the user will already see the exit through regular GDB output, in that same terminal. */ if (!remote_connection_is_stdio ()) { if (ourstatus->kind == TARGET_WAITKIND_EXITED) fprintf (stderr, "\nChild exited with status %d\n", ourstatus->value.integer); else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED) fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", gdb_signal_to_host (ourstatus->value.sig), gdb_signal_to_name (ourstatus->value.sig)); } if (connected_wait) server_waiting = 0; return ret; }
ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options, int connected_wait) { ptid_t ret; if (connected_wait) server_waiting = 1; ret = (*the_target->wait) (ptid, ourstatus, options); if (ourstatus->kind == TARGET_WAITKIND_EXITED) fprintf (stderr, "\nChild exited with status %d\n", ourstatus->value.integer); else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED) fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n", gdb_signal_to_host (ourstatus->value.sig), gdb_signal_to_name (ourstatus->value.sig)); if (connected_wait) server_waiting = 0; return ret; }
static void i386_linux_resume (struct target_ops *ops, ptid_t ptid, int step, enum gdb_signal signal) { int pid = ptid_get_pid (ptid); int request; if (catch_syscall_enabled () > 0) request = PTRACE_SYSCALL; else request = PTRACE_CONT; if (step) { struct regcache *regcache = get_thread_regcache (pid_to_ptid (pid)); struct gdbarch *gdbarch = get_regcache_arch (regcache); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ULONGEST pc; gdb_byte buf[LINUX_SYSCALL_LEN]; request = PTRACE_SINGLESTEP; regcache_cooked_read_unsigned (regcache, gdbarch_pc_regnum (gdbarch), &pc); /* 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 (target_read_memory (pc, buf, LINUX_SYSCALL_LEN) == 0 && memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0) { ULONGEST syscall; regcache_cooked_read_unsigned (regcache, LINUX_SYSCALL_REGNUM, &syscall); /* Then check the system call number. */ if (syscall == SYS_sigreturn || syscall == SYS_rt_sigreturn) { ULONGEST sp, addr; unsigned long int eflags; regcache_cooked_read_unsigned (regcache, I386_ESP_REGNUM, &sp); if (syscall == SYS_rt_sigreturn) addr = read_memory_unsigned_integer (sp + 8, 4, byte_order) + 20; else addr = sp; /* Set the trace flag in the context that's about to be restored. */ addr += LINUX_SIGCONTEXT_EFLAGS_OFFSET; read_memory (addr, (gdb_byte *) &eflags, 4); eflags |= 0x0100; write_memory (addr, (gdb_byte *) &eflags, 4); } } } if (ptrace (request, pid, 0, gdb_signal_to_host (signal)) == -1) perror_with_name (("ptrace")); }