After I set breakpoint, the gdbserver will go wrong. In gdb side will complain that "PC register is not avaliable".
This is main problem this week I meet. Now the gdb can attach to the gdbserver, and run the continue command. Sadly to say, it just can resume the inferior one time because can't set breakpoint yet.
I think the problem is in fetch_register(), I will solve this soon.
According to Youpi's adivice, I planing build gdbserver from scratch. As say, implement the basic gdbserver first, then add more feature one by one. But I also borrow code from the gdb part.
Reference for the implementation of the lynxOS port of gdbserver(because this port is much simpler than linux's), I have summarized the basic framework of how to implement a gdbserver.
1. Implement gnu_create_inferior(); which fork and exec the inferior and initialize the process list. The Hurd port of gdb have two specific core structures, such as structure inf which describe the state of the inferior and structure proc which describe the thread info of the inferior. And now I have put this two structures into gdbserver's process list and thread list reference by the pointer private_data and target_data respective.
2. Implement gnu_wait_1(). which does the actual work of set the wait_status. This is the most import function in gdbserver. Gdbserver only care of this three wait_kinds,TARGET_WAITKIND_EXITED,TARGET_WAITKIND_SIGNALED,TARGET_WAITKIND_STOPPED and should take care of the SIGNAL_TRAP when meet TARGET_WAITKING_STOPPED.
3. Implement the gnu_remuse() which recover the inferior's execution.
Now I have meet a tiny problem, when I use gdb to attach gdbserver, it replied "Remote connection closed". I will debug it and fix this. Before this weekend, my gdbserver should work I think.
This week I have try to build gdbserver on hurd. And it works, but can't do any debugger stuffs, just a program named gdbserver which stays in gdb's build hierarchy.
When I begin to add function pointer to structure target_ops one by one, I have met a design problem, as says, how to implement gdbserver on GNU/Hurd? Should I implement gdbserver from scratch and then add features one by one or borrow code from gdb's implemention and then omit useless parts?
The latter, I must say, there are big gap between gdb's interface and gdbserver's. The gdbserver is much simpler than gdb that just care of the target side doesn't consider of the symbol side. Gdbserver implement many interfaces and structures simply than gdb (such like thread-part, target-ops etc). So I don't know how to decide which interface should be omit or simplify.
For instance, There are 6110 lines in the linux-low.c which is the main part of linux gdbserver's implemention.(BTW, there are only 5320 lines in linux-nat.c which is the main part of linux gdb's impemention). And there are only 723 lines in lynx-low.c which is the main part of LynxOS porting.
Which principle should I follow when I make the decision?
This week I have found out how gdb get inferior's signal.
The magic is the TRACED flags!
The first instruction a inferior will execute after the first GDB run command is at 0x24f0 where is in /lib/ld.so _start() (macro RTLD_START defined in [glibc]/sysdeps/i386/dl_machine.h). Which will load the dynamic library and finally call init1()->_hurd_init()->_hurd_new_proc_init()->_hurdsig_init(). It will initialize the signal thread and let it listening on the inferior's msgport. The ptrace_me call will set the _hurdsig_traced variable (BTW, the gdb also will explicit set the _hurdsig_traced by msg_set_init_int() in if_set_traced()).
If _hurdsig_traced is set, whenever the inferior get any signal it will stop itself (by call proc_dostop)
and call proc_mark_stop to notify its father task by send_sigal(SIGCHLD) or by pthread_cond_broadcast() (ps: I am not clear about this function). [glibc/hurd/hurdsig.c post_signal(): line754] When the inferior stop himself, the S_proc_wait() will returned(GDB has called this before), and send a reply message with msgID 24120 to GDB's event port. When GDB come back from the mach_msg(), it has known all things happened on inferior contains the signal of course.
These is exist an exception, GDB can post a signal to the inferior by command signal. This command will use a so called msg_sig_post_untraced() RPC, then the signal thread will not pass the untraced signal to GDB back.
the manual page of wait
wait, waitpid, waitid - wait for process to change state. All of these system calls are used to wait for state changes in a child of the calling process, and obtain information about the child whose state has changed. A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by a signal.
With the help of my mentor and Richard Braun, My code demo HDebugger can continue from a breakpointer.
After add a thread_abort() the inferior can resume from breakpoint. Thread_abort() is to clean up the waiting event on specific thread. In the practice I have also got clear about the asynchronous RPC.
The HDebugger now can insert breakpoint, access inferior's memory and modify registers thus haven't implemented the interactive interface yet. For the incoming mid-evaluate, I don't plan to continue the HDebugger, I will begin to code gdbserver.
BTW, I haven't understand the msg_sig_post() call, how is the signal delivered? As gdb is listening on the inferior's exception port, then gdb post a signal to that port. That says: gdb post a message to herself, and handle it. Seems no use, but the msg_sig_post() is essential when gdb resume a inferior. So there must be wrong in my understand.