1、1VxWorks 调试手段和方法研究VxWorks 是由美国WRS (风河)公司开发的一个运行在目标机上的高性能、可裁剪的嵌入式实时操作系统。目前我们使用的Tornado集成开发环境为设计 VxWorks应用程序提供了一套高效、实用的调试手段和方法。1 启动和终止调试启动 Debugger当配置好目标机和目标服务器以后,可以通过两种方法来启动 Debugger: 在 Tornado Launch 工具栏中单击 ,就可以为当前所选的目标服务器启动一个调试器 从 Tools 菜单中单击 Debugger,在随后出现的 Launch Debugger 窗口的 Targets 下拉菜单中选择一个目标服
2、务器,就可以为其启动一个调试器如果调试器启动成功,在主窗体左下角的状态栏中将出现“Debugger started successfully.”的提示。对应的 Debugger 菜单的下拉选项和 CrossWind 工具栏中的快捷图标将高亮,表示可用。如下图所示.终止调试可以通过以下两种方式终止调试(Stop Debugging): 在以上 CrossWind 工具栏中,单击 图标 在 Debug 下拉菜单中单击 Stop Debugging 选项终止调试将关闭调试器,相应的调试工具选项将变成灰色,如需进行调试,需重新启动调试器。中断 Debugger单击 CrossWind 工具栏中的 图标
3、或选择 Debug 下拉菜单中的 Interrupt Debugger 选项可以中断程序的执行。若当前调试的任务正处于全速运行的状态,可以中断其执行。2 运行程序单击 CrossWind 工具栏中的 图标或选择 Debug 下拉菜单中的 Run 选项,就会出现2Run Task 窗口。如图 1 所示。利用 Run Task 窗口指定需要运行的函数和函数参数。函数参数之间以空格键隔开。参数列表必须是整数或地址,不能是浮点或双精度值、函数调用。选中 Break at Entrypoint 框可以在函数的第一条语句处设置一个临时断点,这样程序一运行就会停在第一条语句处,用户可以执行单步,跳过子函数调
4、用或恢复执行。3 Attach 和 Dettach 一个任务Attach选择 Debug 下拉菜单中的 Attach 选项可以使一个已经运行的任务处于调试状态。如果在此之前正在调试另一个任务,以前的任务就会被释放,脱离调试器的控制,并保持其当前状态(运行或中止) 。如图 2 所示,Attach 窗口显示出运行于目标板上的所有任务的滚动列表。可以在任务列表中选择一个任务,也可以通过在 Attach to 框中键入任务名称(或任务 ID)选择一个任务。Attach 一个任务以后,调试器立即挂起该任务。Attach 窗口的第一项为 System。选择此项可以进入系统调试模式,如果 BSP 配置不支持
5、系统模式,将会显示出错信息。DetachDetach 选项使当前任务脱离调试器的控制,并将任务挂起,在以后需要的时候仍可以通过选择 Attach 使该任务处于调试状态。图 1 Run Task 窗口图 窗口图 2 Attach 窗口3Detach and Resume单击 Detach and Resume 可以使当前任务脱离调试器的控制,并使任务继续执行4 断点断点类型 任务级断点,仅对当前调试任务有效,设置时单击菜单命令Debug|Toggle BreakPoint也可将光标放在源文件处,点击 图标 全局断点,对所有任务都有效,设置全局断点,采用菜单命令Debug|Toggle Globa
6、l Breakpoint,在任务模式下,断点只对当前被调试的任务有效,但是有时候,我们想看看当前被调试任务的动作是否会对另一个任务有影响,而同时又只能调试一个任务,这时我们就必须使用全局断点。全局断点对任何任务都有效,一旦程序执行到此处,不管当前调试任务为何,此任务都将进入Suspend态,然后可以切换到此任务进行调试。 临时断点,设置时选择菜单命令Debug|Toggle temo BreakPoint,临时断点仅中止程序一次,一旦程序在此中止,Debugger自动删除它。临时断点的图标是一个中空的倒三角,与其它断点相区别。 条件断点,只有当条件满足时,断点才起作用。任务级断点和全局断点可以
7、设置成临时断点或条件断点,或临时条件断点。如下描述。设置断点在 Debug 下拉菜单中选择 Breakpoints 就可以设置多个不同类型的断点。如图 3 所示,在 Location 框中键入文件名和行数,选择断点类型(任务级断点或全局断点) ,单击 Add,新的断点就会出现在断点列表中。如果选中了 Externally managed 框,表示该断点是通过其他(非调试器) 途径设置的,如 Tornado Shell。图 3 Breakpoints 窗口4单击 Adcanced 按钮可以打开 Advanced Breakpoint 窗口,如图 4 所示。Condition Expression
8、 输入框允许用户给断点附加条件,只有在此条件满足时,断点才会起作用,程序才会在此暂停。可以在条件框内输入一个整型表达式,或是一个变化的内存值,只要是非零值,就假定此条件为真。Number of times to skip 框指定在导致程序暂停之前允许经历的断点次数。On Break 选项指定了如何处理一个断点: Keep 将断点定义为永久断点 Delete 将断点定义为临时断点,程序经历一次此断点即删除它 Disable 将断点定义为临时断点,程序经历一次此断点即关闭它,以后仍可以经手工使能删除断点为了删除各类断点,使光标指向断点所在的代码行,单击 图标,或使用如图 3 所示的 Breakpo
9、ints 对话框。5 程序执行在调试器的控制下,一旦一个任务被中止了(通常是遇到了一个断点) ,就可以单步运行程序,跳过子程序调用,或恢复程序执行。在 CrossWind 工具栏中与控制程序执行有关的图标如下所示: 中断程序的执行。若当前调试的任务正处于全速运行的状态,可以中断其执行。:使程序继续执行(Continue),F5图 3 Advanced Breakpoint 窗口5:单步(Step Into),F11:单步(Step Over ),F10:跳出当前函数(Step Out),SHIFT+F11Continue程序中止以后,可以使用Debug菜单的Continue命令恢复程序执行。如
10、果没有遇到断点、中断或信号,任务一直运行到结束。Step Into单击Step Into,可以单步执行程序。如果打开了调试器的观察窗口(检查数据、内存和堆栈),窗口中的值会随着程序的单步执行自动更新。如果遇到一个子程序调用,Step Into会单步运行到子程序的第一行,即可以进入调用的子程序。但是当调用了系统子程序和编译时不带调试信息的应用子程序时,Step Into不会进入该子程序。当Editor 窗口的当前视图显示出汇编代码(从View 下拉菜单中选择Disassembly或Mixed,或是当前代码没有调试符号),Step Into将会使程序执行到下一条指令,而非下一条源代码。Step O
11、ver如果需要单步执行程序而不进入其子程序,单击Step Over。Step Over命令与Step Into命令类似,只是在遇到子函数调用时,Step Over会一次将子函数执行完,并停在子函数调用的下一条语句。Step Out当单步运行一个程序时,可能会发现问题出现在当前子函数的上一级调用函数处。这时可以使用Step Ou命令继续执行程序直到当前子函数结束。程序停在子函数调用的下一条语句,Debugger重新获得控制权。Run to Cursor为了使程序执行到一个特定的位置,却不想在此设置断点,可以将光标放在所需的代码行,单击鼠标右键,在弹出的菜单中选择Run to Cursor。6 观
12、察各类信息当程序在调试器的控制下暂停时,可以使用调试器的辅助窗口检查局部变量和全局变量、函数参数、寄存器、目标板内存和执行函数栈。辅助窗口有两种显示方式,docked 或 free-floating。在 Tools|Options|Debugger 窗口中取消 Docking views 选择框,将辅助窗口设为浮动的,就可以随意调整窗口大小和位置。在 CrossWind 工具栏中与观察各类信息行有关的图标如下所示:打开/关闭Watch窗口,可以用来查看全局变量、表达式或其他符号的值,6ALT+3:打开/关闭Variables窗口,用来查看局部变量的值,ALT+4:打开/关闭Registers窗
13、口,用来查看寄存器的值,ALT+5:打开/关闭Back Trace窗口,用来查看当前函数的调用栈情况,ALT+7:打开/关闭Memory窗口,用来查看指定地址的内存内容,ALT+6上述窗口可以同时打开。每次程序在调试器的控制下暂停时,窗口中的内容将会更新。更新时只有那些变化了的值会高亮。WatchWatch 窗口显示了在整个程序运行过程中变量的当前值。Watch 窗口有四页,可以将相关的变量组成一页,方便观察。在 Editor 窗口选择所需的符号并单击鼠标右键,在弹出的菜单中选择 Add to Watch 就可以将变量添加到 Watch 窗口了,该变量的值允许手工修改。在 Watch 窗口中单
14、击鼠标右键,在弹出的菜单中可以选择添加、删除变量。Variabe单击Debug下拉菜单的Variable命令或工具栏中的Varible图标,就可以打开显示局部变量的Variable窗口。Variable窗口总是显示当前执行函数的局部变量的值。如果程序跳到另一个函数,新函数的局部变量就会取代旧函数的局部变量显示在Variable 窗口中。Variable窗口中的局部变量是由Tornado自动加入删除的,无需用户的手工操作,但允许手工修改局部变量的值。Register单击Debug下拉菜单的Register命令或工具栏中的Register 图标,就可以打开显示寄存器值的Register窗口。窗口中
15、的内容取决于目标板的结构。在Tools|Options|Debugger窗口中取消Docking views选择框,将窗口设为浮动(free-floating)的,窗口的标题就会显示出与芯片结构有关的信息,如对于PowerPc系列显示为ppc。可以手工修改寄存器的值。但是Tornado的Register窗口只能显示出目标板CPU 的有限的几个通用寄存器和特殊功能寄存器,对于开发与硬件结构紧密相关的底层应用程序不是很方便。据技术支持人员介绍,可以安装Single Step for Tornado,使用我们在pSOS中已经非常熟悉的Single Step调试器来解决这个问题。Backtrace利用
16、Backtrace窗口可以检查程序运行到当前函数之前的函数调用顺序,即函数调用栈。在Backtrace窗口中双击任一函数,可以将Editor 窗口的光标移至该函数内发生函数调用处。但此举并没有改变程序的运行流程,只是方便用户检查程序以前的函数调用情况,此时的7光标会改变颜色,与程序正常运行时的光标相区别。MemoryMemory窗口显示出从指定起始地址开始的一部分目标内存值。调试器将起始域中键入的每一个起始地址保存下来,可以从下拉列表中选择一个以前显示过的地址。单击 按钮可以更新内存显示。Memory窗口中显示的内存值不能手工修改。如果想修改某一地址的内存值需要通过Shell命令m来完成。在T
17、ools|Options|Debugger窗口中修改Memory Window 选项可以改变Memory 窗口中的内存值的显示方式。7 调试方法VxWorks支持两种调试模式 : 任务模式调试(Task Mode Debug) 系统模式调试(System Mode Debug)7.1 任务模式调试对单个任务进行调试,其他任务和中断将照常运行。缺省为任务级调试模式,选择菜单Debug|Attach,然后选中要调试的任务即可 对该任务进行调试。一个Debugger一次只能调试一个任务,如果要对另一个任务进行调试,需通过Attach窗口选择该任务,Debugger就会切换到该任务调试。在任务级调试模
18、式下,TargetServer和TargetAgent通过中断方式进行通信 ,因此不能调试中断程序。任务级断点在任务级调试模式下,任务级断点仅对当前调试任务有效,程序运行中若遇到非调试任务中的任务级断点,将忽略此断点。全局断点对所有任务都有效。一旦程序执行到全局断点处,不管当前调试任务为何,包含此全局断点的任务都将进入Suspend状态,如果该任务非当前调试任务,可以通过Attach命令将调试器切换至此任务调试。在任务级模式下调试多任务在任务级调试模式下调试多任务必须使用全局断点。本例中的源程序如附录所示。具体调试步骤如下: 启动VxSim仿真器,下载应用程序的目标代码 启动调试器,分别在任务
19、TaskA和任务TaskB中设置全局断点 选择Run|MultiTaskTest,在Run Task窗口中选中Break at Entrypoint框,程序即会在MultiTaskTest任务的入口点暂停 单步程序,当程序运行经过产生任务TaskA后,可以在browse窗口观察到此时产生8的TaskA已经被挂起,因为在TaskA中设置了一个全局断点 选择Attach|TaskA使调试器切换到调试TaskA 单步运行完TaskA,选择Attach|tDbgTask, 使调试器返回继续调试MultiTaskTest 可以用同样的方法调试TaskB7.2 系统模式调试把整个系统当作一个任务进行调试,
20、因此可以调试中断。断点对所有的任务都起作用。在 Attach 窗口选择 System 可以进入系统级调试模式,进入系统级调试模式将中止整个目标系统:所有的任务,内核和 ISR。 此时 TargetServer 和 TargetAgent 通过轮循方式进行通信。所以,只有支持 END 模式的网络才可以支持系统模式调试,而串口就两种都支持。目标代理的配置调试器工作在何种模式需要与目标代理的配置保持一致。目标代理可以配置成以下三种模式: 任务模式,代理是作为一个 VxWorks 任务运行的。调试也是在一个任务的基础上进行的,可以将任务独立出来而不影响目标系统的其余部分。 系统模式,代理运行于 VxW
21、orks 之外,可以将被调试的应用程序与 VxWorks 视为一个单线程的任务。在此模式下,当目标运行遇到一个断点,VxWorks 和应用程序都会停止并锁住中断。这种模式的最大优点是可以单步 ISR。 双模式,同时配置了两种代理:一个任务模式代理和一个系统模式代理。一次只能激活一个代理,可以通过调试器(选择 Attach|tTask、Attach|system)或 Shell命令(sysResume/sysSupend)在两种模式之间切换。END(Enhanced NetWork Driver)模式的网络支持双模式。为了支持系统模式代理,目标通讯路径必须工作在轮询方式(因为即使系统挂起,外部代
22、理也需要和主机进行通讯) 。因此通讯路径的选择影响可用的调试模式。可以在配置 VxWorks 映象时配置目标代理。如果需要配置支持双模式的目标代理,可将工作台的 VxWorks 窗口中 development tool components|select WDB connect 选项设为WDB END driver connrction,并选中 development tool components|select WDB mode 中的WDB system debugging 和 WDB task debugging。如图 4 所示。图 4 配置双模式目标代理9只有使用了 END 驱动器(具有
23、一个轮询接口)的目标板才支持双模式代理。在 END连接下,代理直接使用 END 驱动器而非 UDP/IP 协议栈。可见,调试器支持双模式的前提是: 下载配置了双模式代理的 VxWorks 映象 目标板使用 END 驱动器在仿真器环境下调试应用程序时,缺省的用于仿真器的 VxWorks 映象的 WDB agent connection 为 WDB simulator pipe connection,WDB mode 支持双模式。因此无需另外配置即可使调试器工作在双模式下。在系统级模式下调试多任务在系统级模式下的断点对所有任务都有效。值得注意的是,在系统级调试模式下运行一个程序不能使用 run 指
24、令,必须采用 Shell 命令 sp。如果使用了 run 命令,系统将会自动恢复任务级调试模式。Shell 工具提供了许多在系统级调试时常用的命令: sysSuspend,进入系统模式并中止目标系统 sysResume,返回任务模式,恢复目标系统的执行 agentModeShow,显示当前调试模式(任务级或系统级) sysStatusShow,显示系统上下文状态(挂起或运行) b, 设置系统级断点,在任何任务,内核或ISR中遇到了断点,整个系统停止运行 c, 恢复整个系统运行,但仍处于系统模式 i, 显示系统上下文状态和代理模式 s, 单步整个系统 sp, 添加一个任务至执行队列中,在系统模式
25、下只能通过sp来启动新任务,而不能运行Debugger的run 命令具体的调试步骤如下: 启动VxSim仿真器,下载应用程序的目标代码 启动调试器。在Debug下拉菜单中Attach窗口中选中Attach|system,进入系统级调试模式,此时会出现一个显示系统汇编代码的窗口,整个系统处于停止状态 分别在 MultiTaskTest、TaskA 和 TaskB 的入口设置断点 打开 Shell 窗口,键入 sp MultiTaskTest 命令,产生一个 MultiTaskTest 任务 在 Shell 窗口中键入 c,程序继续执行,并停在 MultiTaskTest 的入口 单步程序,产生
26、TaskA,继续(continue)执行,程序运行到任务 TaskA,并在其入口处暂停,可以单步调试 TaskA,观察 Browse 窗口的 Tasks 信息显示此时已经产生 t1 和 TaskA,两个任务均处于 ready 状态10 继续单步,执行完 TaskA 后程序返回 MultiTaskTest,单步程序,产生 TaskB 单击 Continue 键,程序运行到任务 TaskB,并在其入口处暂停,可以单步调试TaskB,观察 Browse 窗口的 Tasks 信息显示此时已经产生 t1 和 TaskB,两个任务均处于 ready 状态 执行完 TaskB 后,程序返回 MultiTas
27、kTest,继续执行,直到结束该任务。任务执行的先后顺序与任务的优先级有关,可以尝试修改优先级,观察程序执行的过程。在系统级模式下调试中断程序中断服务程序只能在系统调试模式下调试,不能在任务调试模式下调试。因为中断服务程序是作为系统的一部分运行,不是以任务方式运行,因此不需要为它产生任务。本文以usrClock( )为例说明中断服务程序的调试过程。 usrClock( ) 是连接到系统时钟的中断处理函数,当VxWorks运行时,每遇到一个系统时钟tick就会调用一次usrClock( )函数。仿真器不支持对此中断函数的调试,必须在目标板环境下调试。具体步骤如下: 启动并配置好FTP服务器,启动
28、超级终端,给目标板上电,修改Boot参数,下载VxWorks映象 在Tornado环境中启动相应的目标服务器,启动调试器 在Debug下拉菜单选择Attach|system进入系统调试模式 启动Shell,在Shell窗口中输入以下命令为usrClock( )设置断点:b usrClock 单击Continue,继续执行程序,会发现程序将停在usrClock入口的断点处8 文件组织工作台的 File 窗口显示各工程包含的 C 文件,选中一个工程单击右键,在弹出菜单中选中 Dependencies 选项,可以将 C 文件中的自定义的头文件加到 External Dependencies 目录下。但是编译器并不知道该头文件的具体位置,可以在该工程的 Build|Properties 窗口的C/C+ Complier 信息中添加-I 命令行,将头文件的全路径告知编译器。如附录中的 tt.c 文件中包含了一个自定义的 hello.h 头文件,为了方便文件的组织,此头文件与 tt.c 放在不同的目录中,这时在编译信息中增加行命令-ID:/torProjects/Project1/h,编译器即可在此目录下找到 hello.h 文件。如图 5 所示。图 5 在编译器的命令行中包含头文件路径