[GSoC weekly report#8]implement basic gdbserver

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.

 

[GSoC weekly report#7]build gdbserver on GNU/Hurd

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?

[GSoC weekly report#6]How gdb get inferior's signal?

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[1](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.

[1]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.

[GSoC weekly report#5]begin coding on gdbserver

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.

 

[GSoC weekly report#4]can't resume from a breakpoint

This is my code of HDebugger under GNU/Hurd.  The mainly problem is that it can set a breakpoint but can't resume from it.

The inferior program is just like a hello_world but contains two printf() call. Firstly, I set a breakpoint at the second printf() call, the address if find in the output by objdump -d.

Now, I can get the exception message (which msg.id==2400) from the mach kernel when the inferior hit the breakpoint. When get the message, I recovery the breakpoint of the original code, and set the thread_state by minus the eip register . Then post a signal_0 to it. At last I call thread_resume() try to continue inferior. But I got nothing, the thread is just keeping hang. If I use gdb to attach the inferior when I got the exception message, I can continue the inferior by type "continue command" in gdb' shell.

Answer to  last week:

  1. If  I don’t call proc_wait_request()first in my debugger demo, the mach_msg() call  will never return. This is because the inferior is suspended after execl(), so nobody will send message to us if we don't do a request initiatively.
  2. Is  there exist any specific running sequence between father and child task after fork()? By default, after fork(), the father process run first, so we have a chance to see the execl() to destroy the old threads in child process.
  3. How execl() go? It will destroy the two old threads(main thread and signal thread) forked from the parent process.  Then create a new main thread to run the execute file in execl() parameter. The funny thing is when to create the new signal thread? Never create the signal thread unless an exception appears(NO! The signal thread is initialize early and loop listening on the msgport). This is also the answer to question 4.
Next week goal:
Finish HDebugger and begin to code the gdbserver!