先了解一下访问字符设备(这里指读键盘)的一般过程
sys_read调用tty_read函数,如果tty_table[0].secondary为空就一直睡眠。keyboard_interrupt函数执行时,先将数据从键盘拷贝到tty_table[0].read_q中,然后调用do_tty_interrupt函数将tty_table[0].read_q中的未读数据拷贝到tty_table[0].secondary,一旦tty_table[0].secondary中有数据了,就调用wake_up唤醒进程,继续执行tty_read函数,将tty_table[0].secondary中的数据读到buf中。
将数据拷贝到队列和从队列中读取数据的过程:
由头指针head和尾指针tail管理,队列为空时head和tail为0,每拷进一个字符,头指针head,每读取一个字符,尾指针tail加1加1,所以队列中的未读字符串就是queue[tail:head+1]。另外要注意到队列尾部要回绕到首部。
第一关 键盘的读取过程分析
第一问 函数 sys_read 的参数中记录的用户缓冲区地址(段内偏移)是多少?
直接在sys_read处设置断点查看buf即可
注意文件描述符fd值为0,表示sys_read函数在读0号终端这个文件
第二问 函数 tty_read 开始运行时,0 号终端的 read_q 队列的头指针(数组下标)和尾指针分别是多少?
继续在tty_read处设置断点,查看tty_table[0].read_q即可
第三问 键盘中断处理程序开始运行时,0 号终端的 read_q 队列的头指针和尾指针分别是多少?
键盘中断处理程序就是keyboard_interrupt函数,反汇编,继续在入口地址稍后一点设置断点跳转(注意不能直接在入口处设置),这是需要在键盘输入,本关要求敲入回车,所以切换到boch虚拟机按enter键即可。然后查看tty_table[0].read_q。此时头尾指针都还未变化
第四问 函数 do_tty_interrupt 开始运行时,0 号终端的 read_q 队列的头指针和尾指针分别是多少?该队列中的未读取字符串是什么?0 号终端的 secondary 队列的头指针和尾指针分别是多少?
继续在do_tty_interrupt处设置断点,查看tty_table[0].read_q和tty_table[0].secondary。此时已经将数据从键盘拷贝到tty_table[0].read_q中,所以read_q的头指针加1(表示读入1个字符)。未读字符串是read_q[0] = "\r"
第五问 函数 wake_up 开始运行时,0 号终端的 read_q 队列的头指针和尾指针分别是多少?0 号终端的 secondary 队列的头指针和尾指针分别是多少?该队列中的未读取字符串是什么?
继续在wake_up处设置断点,查看tty_table[0].read_q和tty_table[0].secondary。此时do_tty_interrupt函数已经将tty_table[0].read_q中的未读数据拷贝到tty_table[0].secondary,所以read_q尾指针加1(表示已被读走一个字符),secondary头指针加1(表示读入一个字符)。维度字符串就是secondary[0] = "\n"
第六问 函数 tty_read 结束时,0 号终端的 secondary 队列的头指针和尾指针分别是多少?用户缓冲区的头 2 个字节是什么?
继续在tty_read函数结束处设置断点(288行),查看tty_table[0].secondary。此时tail加1(表示一个字符被读走并放入了sys_read的参数buf中)
然后查看用户缓冲区的前两个字节
结果
第二关 从键盘的一行数据中读取一个字符
原理和操作都和第一关类似,在此仅给出操作序列和解释
(gdb)b sys_read
(gdb)c //确定读的是0号终端
(gdb)b tty_read
(gdb)c
(gdb)p tty_table[0].read_q //获取第一问答案
(gdb)b do_tty_interrupt
(gdb)c
在bochs虚拟机输入abc然后回车
(gdb)p tty_table[0].read_q
(gdb)p tty_table[0].secondary //获取第二问答案
(gdb)b wake_up
(gdb)c
(gdb)p tty_table[0].read_q
(gdb)p tty_table[0].secondary //获取第三问答案
(gdb)c
(gdb)c
(gdb)c //跳到第三次运行do_tty_interrupt
(gdb)p tty_table[0].read_q
(gdb)p tty_table[0].secondary //获取第四问答案
(gdb)c //第三次运行wake_up
(gdb)p tty_table[0].read_q
(gdb)p tty_table[0].secondary //获取第五问答案
(gdb)c
(gdb)c
(gdb)c
(gdb)c
(gdb)c
(gdb)c
(gdb)c //跳到第七次运行do_tty_interrupt
(gdb)p tty_table[0].read_q
(gdb)p tty_table[0].secondary //获取第六问答案
(gdb)c //第七次运行wake_up
(gdb)p tty_table[0].read_q
(gdb)p tty_table[0].secondary //获取第七问答案
(gdb)p tty_table[0].secondary.data
(gdb)b tty_io.c:288
(gdb)c
(gdb)p tty_table[0].secondary
(gdb)p current->start_code + buf
(gdb)x/2bx 0x40254fb //获取第八问答案
(gdb)quit
注意:在bochs虚拟机输入一个字符时就会自动跳回gdb,并且输入字符不会显示,但按要求输入abc回车就行了
结果文章来源:https://www.toymoban.com/news/detail-482989.html
第三关 观察从键盘输入的口令
第一问 程序 passwd 会在几号进程中执行?
在do_execve处设置断点,一直continue,直到需要我们从键盘输入,此时输入passwd,以执行这个文件
第二问 上述进程第一次开始执行函数 tty_read 时,0 号终端的 secondary 队列的头指针和尾指针分别是多少?该队列的 buf 数组中记录的字符串是什么?
在tty_read处设置断点跳转,查看tty_table[0].secondary即可
第三问 上述进程第一次执行完函数 tty_read 时,0 号终端的 secondary 队列的头指针和尾指针分别是多少?该队列的 buf 数组中记录的字符串是什么?
在tty_read结尾处设置断点跳转,此时在虚拟机内输入密码secret回车(注意密码不会显示出来)。查看tty_table[0].secondary即可
结果
文章来源地址https://www.toymoban.com/news/detail-482989.html
到了这里,关于课堂练习6.2:对字符设备的访问的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!