Chinaunix首页 | 论坛 | 博客
  • 博客访问: 515568
  • 博文数量: 95
  • 博客积分: 5168
  • 博客等级: 大校
  • 技术积分: 1271
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-28 23:31
文章分类

全部博文(95)

文章存档

2013年(2)

2012年(3)

2011年(1)

2010年(8)

2009年(81)

分类: LINUX

2009-08-30 16:16:52

-----------------------------------------------------------
本文系本站原创,欢迎转载!

转载请注明出处:http://sjj0412.cublog.cn/

-----------------------------------------------------------

下面以一个实例来说明:

    当我们执行gdb xx时,就会fork(),ptarce(ptraceme)然后execve(xx),这时发现ptraceexcve创建后就会使xx 阻塞TASK_INTERRUPTIABLE.

    然后我们设置bp,这时bp地址所在单元换成trap指令。

    run,xx运行,然后在bp处进入trap中断程序,然后就进入do_signal,这是current->stateptrace,所以不会执行ptrace_cancel_bpt(current);然后就supsend,通知gdb,gdb然后就读取系统信息,并恢复当前pc指令,即将trap指令换成真正的指令。当用户执行next时,gdb设置为single_step,然后就wake_up xx,xx这是就发现是singlestep,就会执行ptrace_set_bpt(current),这个根据分支预测添加一个临时断点。然后就执行上面断点指令,然后在下一条指令处再次trap中断,,这次gdb不用自己并恢复当前pc指令,即将trap指令换成真正的指令,因为这次是singlestep状态,这时ptrace_cancel_bpt(current)会执行,所以不需要gdb作恢复工作,但是第一次进入singlestep需将断点指令恢复为trap insn;

       如果这时再执行continue,则取消single_step即可并会ptrace_cancel_bpt(child);这样就会和最开始状态一样。

       case PTRACE_CONT:

                     ret = -EIO;

                     if (!valid_signal(data))

                            break;

                     if (request == PTRACE_SYSCALL)

                            set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

                     else

                            clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

                     child->exit_code = data;

                     /* make sure single-step breakpoint is gone. */

                     child->ptrace &= ~PT_SINGLESTEP;

                     ptrace_cancel_bpt(child);

                     wake_up_process(child);

                     ret = 0;

                     break;.

 

#define PT_SINGLESTEP_BIT   31

#define PT_SINGLESTEP           (1<

 

进入断点后:为了能够恢复原来断点(因为可能接下来执行的指令又会调到这里,但是这里在断点执行时将断点消除了,这样就不能再次断点了,所以尽快将这个恢复断点,最好方案是执行下一条指令的时候,恢复这个断点),需要至少执行一个step,不论用户在断点后执行stepnext还是run,continue

设置单步

用户层设置单步:

     X86设置单步是唤醒进程,设置为singlestep标识,并标志TF标志位。

       case PTRACE_SINGLESTEP:      /* set the trap flag. */

              ret = -EIO;

              if (!valid_signal(data))

                     break;

              clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

              set_singlestep(child);

       //设置TF标志位,这个标识的是用户态的EFLAGS,所以只有用户态的程序执行才会单步,实际上也需要如此,因为应用程序就是用户态。

              child->exit_code = data;

              /* give it a chance to run. */

              wake_up_process(child);

              ret = 0;

              break;

 

 static void set_singlestep(struct task_struct *child)

{

       struct pt_regs *regs = get_child_regs(child);

 

       /*

        * Always set TIF_SINGLESTEP - this guarantees that

        * we single-step system calls etc..  This will also

        * cause us to set TF when returning to user mode.

        */

       set_tsk_thread_flag(child, TIF_SINGLESTEP);

 

       /*

        * If TF was already set, don't do anything else

        */

       if (regs->eflags & TRAP_FLAG)

              return;

 

       /* Set TF on the kernel stack.. */

       regs->eflags |= TRAP_FLAG;

 

       /*

        * ..but if TF is changed by the instruction we will trace,

        * don't mark it as being "us" that set it, so that we

        * won't clear it by hand later.

        */

       if (is_at_popf(child, regs))

              return;

      

       child->ptrace |= PT_DTRACE;

}

 

arm:

       case PTRACE_SINGLESTEP:

                     ret = -EIO;

                     if (!valid_signal(data))

                            break;

                     child->ptrace |= PT_SINGLESTEP;

                     clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

                     child->exit_code = data;

                     /* give it a chance to run. */

                     wake_up_process(child);

                     ret = 0;

                     break;

      

Arm硬件调试器原理:

       其实硬件调试器和软件调试器,原理基本一样:

       硬件调试器相当于gdb,被调试的arm芯片,相当于被调试的应用程序。

       软件调试中

                     应用程序进入断点了,通过trap中断停止自己,并通知gdb.

       硬件调试中:

                     arm板遇到硬件断点了,会进入调试模式,调试模式是由dclk提供时钟,而这个由jtag产生,当没有jtag命令时就没有时钟,故也达到了停止作用,而这里获取调试状态,是调试器不断轮询扫描链2读取debug_state_register的是否进入调试状态,这样也就达到断点通知目的了。

Debug State Register

     DBGACK 信号用来标识当前系统是否处于调试状态,当ARM7TDMI 进入调试状态

后,该信号会被自动置1   所以,通过查询该位,就可以判断ARM7TDMI 当前的

 

 

软件调试器的断点:

              是通过向内存写入int3,trap指令来达到断点目的。

 

 

 

 硬件调试器断点:

              arm有两组观察点寄存器 ,可以将其中一组设置为读指令,地址屏蔽,Value为特定值比如eeeeeeee。这时要将一个内存地址设为断点,只需将其值替换为eeeeeeee,这样当运行到此地址时,就会匹配,就会进入调试模式。

 

软件调试单步:

     硬件调试器单步,这个就是借鉴gdb的单步模式,所以,基本一样。 
阅读(1402) | 评论(0) | 转发(0) |
0

上一篇:gdb调试工作机制(1)

下一篇:gnome启动分析

给主人留下些什么吧!~~