课堂练习6.2:对字符设备的访问

先了解一下访问字符设备(这里指读键盘)的一般过程

 

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回车就行了

结果

第三关 观察从键盘输入的口令

第一问 程序 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即可

结果

  • 17
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值