From: quntmec@hotmail.com
To: qf.hao@hotmail.com
Subject: 关于《UNIX技术内幕》的勘误及遇到的问题_23
Date: Fri, 3 Feb 2012 23:47:25 +0800
郝先生,
最近碰到的问题如下:
1、有关 ptrace 的例子
(1)567页,例1的输出中,最后2行的顺序似乎错了,应为如下:
....
End breakpoint in child
The child resumed.
理由如下:
当
执行第27行代码时,即“ptrace(7,id,0,0)”,它与其他的ptrace语句是不同的,它会返回1(其他一般是返回0)而退出SSTOP,
这样子进程就会继续,具体是
stop->issig->trap(这里->是返回的意思),最后退出debug。接着执行第16行,打印出“End
breakpoint in child”。当子进程中的指令执行完后,且待到其时间片用完后,CPU转而执行父进程,则最后打印“The child
resumed”。
[郝]:你分析的很仔细!子进程虽然在procxmt返回后会继续,但有可能在
子进程打印"End breakpoint in
child“的过程中时钟中断产生,从而切换到父进程执行(因为这时候父进程刚从ipc上被唤醒,优先级更高)。当然,从很多时候来看,子进程先执行的可
能性更大。这里需要加上说明。
(2)如果上面(1)正确的话,那接着的例2也有类似的问题,具体如下(我感觉例2的输出应该如下):
-------------------------------------------
父:Waiting for child to enter SSTOP
子:Start breakpoint1 in child
父:Start debugging child. Here g_x is 0
父:The g_x's value in child is 1
父:Write g_x completed, g_y's value in child is 不确定。(原因1)
子:End breakpoint1 in child
父:The child resumed
子:End breakpoint2 in child(原因2)
到这里子进程完了,但父进程无法继续(原因3)
-------------------------------------------
原因1:在第5行,g_y是没有被赋予初始值的,因此在第33行读出的 g_y 的值不确定
[郝]:从程序上来看是这样的,只是有些编译器生成的代码会在调用main之前,自动把非初始化的数据段清0,当然这里是不严谨,并非所有编译器都会这么做。下一版会修改。
原因2:当第36行调用 wait函数 时,执行的是 wait函数 的 第38~39行(527页),即清 STRC 和
SWTED;且随后跳回至loop标号循环(即wait函数的第6行),直至时间片用完。当子进程获得CPU后,是执行 stop函数
的第12行(if语句),由于第一个条件成立(在wait函数里已将STRC清0),因此子进程退出SSTOP,最终退出debug,继而打印“End
breakpoint2 in child”
[郝]:第25行和第36行的wait作用一样,都是
等待子进程进入到SSTOP状态,然后wait返回。第一次在第25行的wait并不会清除STRC标志,当子进程执行第15行的debug后,触发断点
信号,从而子进程进入到SSTOP状态,第25行的wait返回。父进程在第34行的ptrace调用导致子进程退出SSTOP状态,从第15行返回。这
样第36行的wait由于第18行的debug调用而再次返回,注意这时候子进程并不会退出SSTOP状态,而是“停顿”等待父进程的操作,最后父进程第
43行的ptrace调用使子进程从第18行的debug返回。下一版考虑加上注释
原因3:这里说无法继续可能不太恰当,应该是父进程在第36行处无限循环等待,而第37行之后的代码将无法执行。
2、有关debugger实现里的问题
579页,StepOut函数 的第5行,不太明白它的意思。具体如下:
第3行:r5 = ptrace(3,id, U_AR0_OFFSET,0) + R5*2 - 0O140000;
第4行:r5 = ptrace(3,id,r5,0);
第5行:r5 = ptrace(2,id,r5,0);//不明白它的意思
第6行:pc = ptrace(1,id,r5,0);
我的理解是:
第3行:获取r5在内核栈里的addr。参考192页,图7-2
第4行:获取r5的内容,即pc。最后 r5=pc [郝]:这里是读取子进程内核态下R5寄存器的值,也就是子进程用户栈指针。
第5行:? [郝]: 读取子进程用户栈顶的值(R5),也就是子进程当前函数的返回地址PC。 应改为:pc = ptrace(2, id, r5,0)
第6行:获取pc对应的指令 [郝]: 这一行应该是多余的。下一版改正。
3、有关 ptrace 的应用
对
于568页,例3,里面的 wly.out,如果将 debug
去掉,在“b=0”后面增加一句“printf("b=%d\n",b);”。这就变成了我们日常调试的方式,也可以测试变量b的变化。单从效果上来看,
与书里的例3是一致的。那为何要用ptrace呢?我不是钻牛角尖,我明白你是想通过简单的例子说明ptrace的用法!我真正的疑惑是在什么情况下使用
ptrace?我相信会在调试的时候使用,但一般调试什么方面的内容会使用到ptrace呢(不包括在书里提到过的例子)?
[郝]:这是一个好问题!ptrace一般是开发专门的调试器的时候才用到,比如gdb或dbx。就一般的应用程序而言,很少使用。如果确实要使用,那可以在普通方法比如printf达不到的
情况下使用,比如读取进程内核栈上的一些数据,当然使用ptrace的时候被调试进程(一般是子进程)也需要增加一些代码就像例子中的ptrace(-1,...)和debug调用。
此外,勘误:无
Steve
《返璞归真--UNIX技术内幕》在全国各大书店及网城均有销售:
阅读(5450) | 评论(0) | 转发(0) |