Re: gdbstub initial code, v7
On 10/13, Roland McGrath wrote: On 09/10, Roland McGrath wrote: ugdb sets please stop flag and does utrace_control(INTERRUPT). However, in unlikely case the tracee can stop before -report_signal() reporting I don't think this is the right thing to do. When the intent is explicitly to interrupt, there is no reason to stop before the interruption is complete, i.e. report_signal. This means that ugdb_report_quiesce() should never return UTRACE_STOP, and that is all. I'm not sure about this. Ignoring the problems below, why? But what about multitracing? Suppose that (gdb) interrupt happens just before, say, do_report_syscall_entry() and another engine wants to stop. If ugdb_report_quiesce() doesn't return UTRACE_STOP, then gdb will wait until another debugger resumes the tracee. Yes, I do think that's a problem. We want gdb to report back promptly. One possibility is to have report_quiesce notice its argument is UTRACE_EVENT(SYSCALL_ENTRY) and roll back to before the syscall. That is, it enables SYSCALL_ENTRY and SYSCALL_EXIT reporting, then its report_syscall_entry uses UTRACE_SIGNAL_ABORT, report_syscall_exit does syscall_set_return_value(-ERESTARTNOHAND, 0) and then returns UTRACE_INTERRUPT. Now, we'll reenter a UTRACE_SIGNAL_REPORT callback before the system call, and we can stop there without being in any sticky situation. Well, but this doesn't look friendly to other engines... And at first glance this looks a bit too hairy. And, this doesn't cover another case: gdb asks to stop the tracee when it is already stopped by another engine and sleeps in utrace_resume() path. So, I think ugdb should be changed so that signal SIG always works (without reporing this signal) even when the stopped tracee doesn't have the signal context. As for $_siginfo (qXfer:siginfo:read::), I do not know what ugdb should do. Probably it can just report the all-zeroes siginfo or report si_signo = SIGSTOP. Oleg.
Re: gdbstub initial code, v7
But I meant another case, when the stopped tracee doesn't have siginfo. Currently ugdb just sends this signal to tracee, and then it will be reported to gdb. Not sure if this is right or not, I can change this. (or perhap this doesn't matter, I dunno). What do you mean by doesn't have siginfo? You mean non-signal stops? What non-signal stops does ugdb report? Thanks, Roland
Re: gdbstub initial code, v7
On 09/10, Roland McGrath wrote: But I meant another case, when the stopped tracee doesn't have siginfo. Currently ugdb just sends this signal to tracee, and then it will be reported to gdb. Not sure if this is right or not, I can change this. (or perhap this doesn't matter, I dunno). What do you mean by doesn't have siginfo? You mean non-signal stops? Yes. What non-signal stops does ugdb report? (gdb) interrupt ugdb sets please stop flag and does utrace_control(INTERRUPT). However, in unlikely case the tracee can stop before -report_signal() reporting loop (especially in multitracing case). Or it can be already stopped (note: this needs a separate discussion, currently ugdb intentionally doesn't handle this case). And. With the current implementation, even if the tracee stops after ugdb_report_signal() was called, it doesn't setup -t_siginfo. IOW. If the tracee actually recieves a signal, then - qXfer:siginfo:read works - signal SIG works as expected (delivered to tracee) Otherwise - qXfer:siginfo:read reports E01 - signal XX means TXX report. Once again, this can be changed (fixed?), but I am not sure this should be changed. Oleg.
Re: gdbstub initial code, v7
ugdb sets please stop flag and does utrace_control(INTERRUPT). However, in unlikely case the tracee can stop before -report_signal() reporting I don't think this is the right thing to do. When the intent is explicitly to interrupt, there is no reason to stop before the interruption is complete, i.e. report_signal. If you only stop there, then you can always process a signal injection with complete flexibility. The gdb model and the remote protocol doesn't currently have any concept of requesting a stop that is not an interruption. Thanks, Roland
Re: gdbstub initial code, v7
On 09/10, Roland McGrath wrote: ugdb sets please stop flag and does utrace_control(INTERRUPT). However, in unlikely case the tracee can stop before -report_signal() reporting I don't think this is the right thing to do. When the intent is explicitly to interrupt, there is no reason to stop before the interruption is complete, i.e. report_signal. This means that ugdb_report_quiesce() should never return UTRACE_STOP, and that is all. But what about multitracing? Suppose that (gdb) interrupt happens just before, say, do_report_syscall_entry() and another engine wants to stop. If ugdb_report_quiesce() doesn't return UTRACE_STOP, then gdb will wait until another debugger resumes the tracee. What do you think? If you only stop there, then you can always process a signal injection with complete flexibility. Yes, sure (again, currently ugdb does not injection a signal even if the tracee was stopped in report_signal, but of course we can change this). Oleg.
Re: gdbstub initial code, v7
On Thu, 02 Sep 2010 22:06:32 +0200, Oleg Nesterov wrote: I assume that qXfer:siginfo:read always mean Hg thread. It seems so. It is not clear to me what should ugdb report if there is no a valid siginfo. linux_xfer_siginfo() return E01, but gdbserver uses SIGSTOP to stop the tracee, I find error more appropriate in such case. Likewise, it is not clear what should ugdb do if gdb sends $CSIG in this case. Currently GDB does not do anything special, that is if there is siginfo for signal SIGUSR1 but one does $C0B (SIGSEGV) does ptrace reset the siginfo or is left the SIGUSR1 siginfo for SIGSEGV? But this all is minor, I think. As this is being discussed for GDB I would find enough to just make $_siginfo accessible without these details. Thanks, Jan
Re: gdbstub initial code, v7
Oleg Nesterov o...@redhat.com writes: [...] To the point, I had to add printk's to utrace.c to understand what is wrong. Hopefully tomorrow. You might wish to try out systemtap for such purposes. It's easy to insert printk-like tracing at almost any point; monitor variables for changes, pretty-print structs, etc. No recompilation/reboot. - FChE
Re: gdbstub initial code, v7
Currently GDB does not do anything special, that is if there is siginfo for signal SIGUSR1 but one does $C0B (SIGSEGV) does ptrace reset the siginfo or is left the SIGUSR1 siginfo for SIGSEGV? The kernel considers this sloppy behavior on the debugger's part. If you inject a different signal, we expect you should PTRACE_SETSIGINFO to something appropriate, or else that you really didn't care about the bits being accurate. If the resumption signal does not match the siginfo_t.si_signo, then the kernel resets the siginfo as if the debugger had just used kill with the new signal (i.e. si_pid, si_uid point to the ptracer). Thanks, Roland
Re: gdbstub initial code, v7
On Fri, 03 Sep 2010 21:59:06 +0200, Roland McGrath wrote: Currently GDB does not do anything special, that is if there is siginfo for signal SIGUSR1 but one does $C0B (SIGSEGV) does ptrace reset the siginfo or is left the SIGUSR1 siginfo for SIGSEGV? The kernel considers this sloppy behavior on the debugger's part. If you inject a different signal, we expect you should PTRACE_SETSIGINFO to something appropriate, or else that you really didn't care about the bits being accurate. If the resumption signal does not match the siginfo_t.si_signo, then the kernel resets the siginfo as if the debugger had just used kill with the new signal (i.e. si_pid, si_uid point to the ptracer). OK, that seems to me as the best choice. Sorry I did not test/read it. Thanks, Jan
Re: gdbstub initial code, v7
Sorry for the delay, I was distracted. Trying to switch back to ugdb. On 08/31, Jan Kratochvil wrote: ugdb should support qXfer:siginfo, currently accessible only via $_siginfo print/set, though. Still sure this feature should be also implemented one day. Yes sure. This should be simple, although I didn't expect qXfer needs remote_escape_output() and x86_siginfo_fixup(). I assume that qXfer:siginfo:read always mean Hg thread. It is not clear to me what should ugdb report if there is no a valid siginfo. linux_xfer_siginfo() return E01, but gdbserver uses SIGSTOP to stop the tracee, so it always has something to report. But ugdb stop the tracee somewhere else, not in get_signal_to_deliver() path. Likewise, it is not clear what should ugdb do if gdb sends $CSIG in this case. But this all is minor, I think. I was going to send v8 which implements qXfer:siginfo:read and continue with signal, but (oh, as always) hit the unexpected problems. To the point, I had to add printk's to utrace.c to understand what is wrong. Hopefully tomorrow. Oleg.
Re: gdbstub initial code, v7
On Mon, 30 Aug 2010 21:20:40 +0200, Jan Kratochvil wrote: On Mon, 30 Aug 2010 20:58:50 +0200, Oleg Nesterov wrote: - report signals. A bit more code changes than I expected. BTW not sure if it is already the right time for it but to keep ugdb on-par with my linux-nat's re-post today (still not accepted in FSF GDB) That's not true, this functionality needs no gdb/remote.c changes and its correctnes relies just on ugdb (and it is probably not a problem for ugdb). ugdb should support qXfer:siginfo, currently accessible only via $_siginfo print/set, though. Still sure this feature should be also implemented one day. Thanks, Jan
gdbstub initial code, v7
Changes: - report signals. A bit more code changes than I expected. - implement QPassSignals, trivial. Note: $CSIG is not supported yet, and I am not sure I understand how it should work. Next time... #include linux/module.h #include linux/proc_fs.h #include linux/utrace.h #include linux/poll.h #include linux/mm.h #include linux/regset.h #include asm/uaccess.h static int o_remote_debug; module_param_named(echo, o_remote_debug, bool, 0); #define BUFFER_SIZE 1024 #define PACKET_SIZE 1024 struct pbuf { char*cur, *pkt; charbuf[BUFFER_SIZE]; }; static inline void pb_init(struct pbuf *pb) { pb-cur = pb-buf; pb-pkt = NULL; } enum { U_STOP_IDLE = 0, U_STOP_PENDING, U_STOP_SENT, }; struct ugdb { struct list_headu_processes; struct list_headu_stopped; int u_stop_state; struct mutexu_mutex; spinlock_t u_slock; struct ugdb_thread *u_cur_tinfo, *u_cur_hg, *u_cur_hc; wait_queue_head_t u_wait; int u_err; struct pbuf u_pbuf; charu_cbuf[PACKET_SIZE]; int u_clen; sigset_tu_sig_ign; unsigned int u_no_ack:1, u_allstop:1; }; static inline void ugdb_ck_stopped(struct ugdb *ugdb) { spin_lock(ugdb-u_slock); WARN_ON(!list_empty(ugdb-u_stopped) ugdb-u_stop_state == U_STOP_IDLE); WARN_ON(list_empty(ugdb-u_stopped) ugdb-u_stop_state == U_STOP_PENDING); spin_unlock(ugdb-u_slock); } static struct ugdb *ugdb_create(void) { struct ugdb *ugdb; int err; err = -ENODEV; // XXX: ugly. proc_reg_open() should take care. if (!try_module_get(THIS_MODULE)) goto out; err = -ENOMEM; ugdb = kzalloc(sizeof(*ugdb), GFP_KERNEL); if (!ugdb) goto put_module; INIT_LIST_HEAD(ugdb-u_processes); INIT_LIST_HEAD(ugdb-u_stopped); mutex_init(ugdb-u_mutex); spin_lock_init(ugdb-u_slock); init_waitqueue_head(ugdb-u_wait); pb_init(ugdb-u_pbuf); return ugdb; put_module: module_put(THIS_MODULE); out: return ERR_PTR(err); } #define P_DETACHING (1 1) #define P_ZOMBIE(1 2) struct ugdb_process { int p_pid; int p_state; struct list_headp_threads; struct ugdb *p_ugdb; struct list_headp_processes; }; static inline bool process_alive(struct ugdb_process *process) { return !(process-p_state P_ZOMBIE); } static inline void mark_process_dead(struct ugdb_process *process) { process-p_state |= P_ZOMBIE; } static struct ugdb_process *ugdb_create_process(struct ugdb *ugdb, int pid_nr) { struct ugdb_process *process; process = kzalloc(sizeof(*process), GFP_KERNEL); if (!process) return NULL; process-p_pid = pid_nr; process-p_ugdb = ugdb; INIT_LIST_HEAD(process-p_threads); list_add_tail(process-p_processes, ugdb-u_processes); return process; } #define T_STOP_RUN 0 #define T_STOP_REQ (1 0)/* requested by gdb */ #define T_STOP_ALL (1 1)/* vCont;c:pX.-1, for report_clone */ #define T_STOP_ACK (1 2)/* visible to vStopped */ #define T_STOP_STOPPED (1 3)/* reported as stopped to gdb */ /* TASK_TRACED + deactivated ? */ #define T_EV_NONE 0 #define T_EV_EXIT (1 24) #define T_EV_SIGN (2 24) #define T_EV_TYPE(event)((0xff 24) (event)) #define T_EV_DATA(event)(~(0xff 24) (event)) struct ugdb_thread { int t_tid; int t_stop_state; int t_stop_event; struct ugdb *t_ugdb; struct ugdb_process *t_process; struct list_headt_threads; struct list_headt_stopped; struct pid *t_spid; struct utrace_engine*t_engine; }; static inline bool thread_alive(struct ugdb_thread *thread) { WARN_ON((thread-t_tid != 0) != process_alive(thread-t_process)); return thread-t_tid != 0; } static inline void mark_thread_dead(struct ugdb_thread *thread) { mark_process_dead(thread-t_process); thread-t_tid = 0; } /* * The thread should be alive, and it can't pass ugdb_report_death() * if the caller holds ugdb-u_mutex. However
Re: gdbstub initial code, v7
On Mon, 30 Aug 2010 20:58:50 +0200, Oleg Nesterov wrote: - report signals. A bit more code changes than I expected. BTW not sure if it is already the right time for it but to keep ugdb on-par with my linux-nat's re-post today (still not accepted in FSF GDB) [0/9]#2 Fix lost siginfo_t http://sourceware.org/ml/gdb-patches/2010-08/msg00480.html ugdb should support qXfer:siginfo, currently accessible only via $_siginfo print/set, though. Thanks, Jan