[GSoC weekly report#3]dig into the gnu_nat.c

This week I have digged into the GDB source code. I have turn on the gnu_debug_flags in gnu_nat.c, and get about 500 lines output when debugging a hello_world program. Then I try to get clear about the detail of GNU/Hurd follow the output step by step. But I have got a lot of puzzles.

  1. What is the proc server?. And I found that If  I don’t call proc_get_reqeust() proc_wait_request()first in my debugger demo, the mach_msg() call  will never return.
  2. Is  there exist any specific running sequence between father and child task after fork()? And I found the inferior always call the trace_me() in the same time(the trace me printf always in the same line of the output log).
  3. How do the fork() and execl() go? Say there is a father task which contains two threads( one for main thread, and other is the signal thread). After the father call fork(), the child call execl() immediately, how things go? Will execl() destroy the two old threads and then create new ones?
  4. When I set a breakpoint in the hello_world program, I will get five times new thread printf and three threads died printf. If I don't set breakpoint, I only get four times, and two threads died. How to explain this?
  5. How to understand the relationship and difference between structure inf  and structure inferior? I think the inf is low-level presentation of the debugged program, and the other is a high-level presentation. Am I right?
  6. what are the observer_notify_new_thread()  and observer_notify_thread_ptid_changed() do in thread.c?
  7. What are the target_terminal_*() [fork_child.c] like target_terminal_init() and target_ternimal_inferior() do?

Next week goal: solve above questions.

[GSoC weekly report#2]My understand of How exception is thrown and handled in Hurd

This week I have read the <Mach 3 Kernel Principles> and some relate materials. And I have rewritten the MIG use example in <A programmer's guide to the mach user environment>. I put the code in github. Most of the code is stolen from Anand Babu's example.

Now I have known something about the mig basically. I can answer the question of  "What is the S_exception_raise_request()?" .

Firstly, I will describe without debugger stuff. When a task was created, the glibc will created one more thread(so called message thread or signal thread) in the task. The function  _hurdsig_init() [glibc/hurd/hurdsig.c] will initialize the exception port of the other thread in the task, and start the signal thread to listen on all the ports. The signal thread will run the _hurd_msgport_recieve() [glibc/hurd/msgportdemux.c] which invoke the mach_msg_server() [glibc/mach/msgserver.c] with the first parameter of msgport_server() as its demux pointer.

After the initialization, the signal thread is blocked until a exception occur. Whenever an exception occurs(for instance, thread A cause an divide zero exception), the mach kernel will suspend the thread A right now, and the kernel will send a exception message to the thread A's exception port on behalf of A. Meanwhile, our signal thread is already listening on the thread A's exception port. So the mach_msg() will return, and invoke the (*demux)() which is pointer to msgport_server() as described above.

Ok, now we will see the magic of mig. In the last line of msgport_server(), it will return _S_exc_server(). The _S_exc_server() is just an demux who generated by mig  from the mach/include/mach/exc.defs and will call the S_catch_exception_raise() to handle the exception. S_catch_exception_raise() [glibc/hurd/catch-exc.c] deliver the signal by _hurd_internal_post_signal()  [glibc/hurd/hurdsig.c]. Honestly to say, the _hurd_internal_post_signal() function is too complex to understand for me now. I think I will make it clear in the later work. By default, the _hurd_internal_post_signal will invoke the default handler to handle the divide zero exception which just simply terminal the thread A. After this, the whole exception things without debugger is done.

If a task is under the control of gdb, thing will be a little different. Instead of the glibc's _hurd_msgport_recieve(), the gdb will use the the gnu_wait() to listen on the exception port. And then pass the message by (!notify_server()  && !exc_server() && !process_reply_server() && !msg_reply_server()). We only care about exc_server() here, it was generated by the mid from gdb/exc_request.defs like above, and will invoke the S_exception_raise_request() who will handle this exception like the situation in S_catch_exception_raise() above.

This is my understand of how exception is thrown  and be handled.

Again, the next week goal is to finish the debugger demo.

[GSoC weekly report#1]Reading source code and build a debugger demo in Hurd(not complete yet)

Honestly to say, these days I haven't enough time to do the gsoc stuff. The school work had taken almost all of my time. And I am so sorry to that I haven't got any significant progress at the beginning week.

I am reading the gdb source code, and the gnu-nat.c file has captured my eyes. According to the mach's exception model, I have tried to write a debugger demo on Hurd (not completed yet).  But I got some puzzles below:

1) What is the S_exception_raise_request()?

The exception model says: victim raise, victim wait, handler catch, handler take action. In my knowledge, handler catch the notification by invoking mach_msg(), and I finally found this invoke in gun_wait() function. But, I also found something strange like S_exception_raise_request(). The comment says ""The rpc handler called by exc_server ". What is the exc_server? And how to understand this why seems two place to catch the exception notification?

2) what is the role of ptrace in gdb port on Hurd?

I have found only one place to use ptrace like ptrace(PTRACE_TRACEME,..).  The rest directly use the vm_read,vm_write to access the inferior's memory instead of ptrace(PTRACE_PEEKDATA). what's plus, I have found the implementation of ptrace support PTRACE_PEEKDATA under Hurd in glibc.

Next week goal:

1. finish the debugger demo which support modifying the debugged process's memory and inserting breakpoint.

2. continue to read the source code. get clearly with the above questions.

GSoC2013 accept!

一大早收到两封来自google的邮件,终于不是thank you开头,读研这段日子收了好多公司的感谢信(微软、大摩、EMC、新思。。。集满七封是不是可以换一个offer?)google的这句Congratulations确实够振奋我心 🙂

Congratulations! Your proposal "[HURD] Improve the GDB Port for GNU Hurd" submitted to "GNU Project" has been accepted for Google Summer of Code 2013. Over the next few days, we will add you to the private Google Summer of Code Student Discussion List.
Now that you've been accepted, please take the opportunity to speak with your mentors about plans for the Community Bonding Period: what documentation should you be reading, what version control system will you need to set up, etc., before start of coding begins on 17 June.
Welcome to Google Summer of Code 2013! We look forward to having you with us.
With best regards,
The Google Summer of Code Program Administration Team
少年继续努力!为开源世界贡献一份力!

[逻辑题]放下那个坏球!

题目很简单,一共有12个小球,其中有一个的质量和其他不一样,问,如何用一架天平只称3次就找到那个坏球?

分析:12个球,3次,直觉就是4个球为一组,分3组。任意拿8个球出来称一次。有两种结果,平衡,不平衡。

情况一:天平平衡,说明选中的8个球都是好球,那么坏球一定在未选中的4个里。目标缩小到四个,接下来就好办了,从4个中任选两个,然后再拿两个好球出来称一次,若平衡,则坏球在未选中的两个中,不平衡则在选中的两个中;目标缩小到两个,取一个与好球称一次,结果立现,刚好称了三次。

情况二:天平不平衡,说明未选中的4个皆为好球,目标缩小为8,此种情况略复杂。对8个目标球进行编号1-8,并记天平左边盘子为A,右边盘子为B。则第一次称可以表示为A=(1,2,3,4),B=(5,6,7,8)。 假设A<B(因为不平衡,总有一边盘子重,用此记号方便描述,无他)。

第一个关键点来了我承认我是通过枚举的方式得到的),第二次称重方式为,A=(1,5,6),B=(2,7,0)。0表示好球,因为第一次称已经确定了4个好球。

此回合的结果有三。

A=B:说明坏球在3,4,8中。目标缩小到3个,但是现在只剩一次称的机会,需要确定三个球,貌似是不可能。但是,因为第一次称有额外的信息,即第一次称的结果A<B,说明要么是3,4球中有一个是轻的,要么是8号球重了。那么只需要把3,4球分别放在天平的两端,平衡则8好球是坏球,并且坏球是重的;不平衡则,轻的那端是坏球,并且坏球是轻的。

A<B:说明坏球在1,7中。目标缩小到2个,直接拿个好球来称一次就出结果。

A>B:说明坏球在2,5,6中。目标缩小到3个,类似上面的分析,额外信息是要么5,6中有一个是坏球,并且是重了;要么是2号球轻了。然后称一次5,6即可出结果。

这道题的关键之处在于,要充分利用前一次的信息来完成推理。

++++++++++++++++++++++++分割线++++++++++++++++++++++++++++++

到这里还没有结束,此题有个变种,13个球最少称几次能找到其中的坏球?

答案还是3!

思路如下:任选8个球称一次,若不平衡,目标缩小到8个,然后用上面的思路即可。

若平衡,则目标缩小为未选中的5个球。其实分析发现两次是可以确定5个球的,再次上编号,1,2,3,4,5。

然后 A=(1,2) B=(3,0),若平衡,说明4,5是坏球,目标为2,结果立现。

若不平衡,A<B,说明要么1,2有一个轻球,要么3是重球。称一次1,2即可。

若A>B,说明要么1,2有一个是重球,要么3是轻球,称一次1,2即可。