分类: 嵌入式
2010-04-09 13:04:36
主要摘自《嵌入式linux应用程序开发详解》——华清远见
嵌入式软件经过编译和链接后即进入调试阶段,调试是软件开发过程中必不可少的一个环节,嵌入式软件开发过程中的交叉调试与通用软件开发过程中的调试方式有很大的差别。在常见软件开发中,调试器与被调试的程序往往运行在同一台计算机上,调试器是一个单独运行着的进程,它通过操作系统提供的调试接口来控制被调试的进程。而在嵌入式软件开发中,调试时采用的是在宿主机和目标机之间进行的交叉调试,调试器仍然运行在宿主机的通用操作系统之上,但被调试的进程却是运行在基于特定硬件平台的嵌入式操作系统中,调试器和被调试进程通过串口或者网络进行通信,调试器可以控制、访问被调试进程,读取被调试进程的当前状态,并能够改变被调试进程的运行状态。
嵌入式系统的交叉调试有多种方法,主要可分为软件方式和硬件方式两种。它们一般都具有如下一些典型特点。
下面主要介绍一下软件调试:
软件方式调试主要是通过插入调试桩的方式来进行的。调试桩方式进行调试是通过目标操作系统和调试器内分别加入某些功能模块,二者互通信息来进行调试。该方式的典型调试器有 Gdb 调试器。GDB 的交叉调试器分为 GdbServer 和 GdbClient,其中的 GdbServer 就作为调试桩安装在目标板上,GdbClient 就是驻于本地的 Gdb 调试器。它们的调试原理图如图4.19所示。
Gdb 调试桩的工作流程:
这样就完成了调试的整个过程。这个方案的实质是用软件接管目标机的全部异常处理及部分中断处理,并在其中插入调试端口通信模块,与主机的调试器进行交互。但是它只能在目标机系统初始化完毕、调试通信端口初始化完成后才能起作用,因此,一般只能用于调试
运行于目标操作系统之上的应用程序,而不宜用来调试目标操作系统的内核代码及启动代码。
gdbserver(1) GNU Development Tools gdbserver(1) NAME gdbserver - Remote Server for the GNU Debugger SYNOPSIS gdbserver tty prog [args...] gdbserver tty --attach PID DESCRIPTION GDBSERVER is a program that allows you to run GDB on a different machine than the one which is running the program being debugged. Usage (server (target) side): First, you need to have a copy of the program you want to debug put onto the target system. The program can be stripped to save space if needed, as GDBserver doesn't care about symbols. All symbol handling is taken care of by the GDB running on the host system. To use the server, you log on to the target system, and run the `gdbserver' program. You must tell it (a) how to communi‐ cate with GDB, (b) the name of your program, and (c) its arguments. The general syntax is: target> gdbserver COMM PROGRAM [ARGS ...] For example, using a serial port, you might say: target> gdbserver /dev/com1 emacs foo.txt This tells gdbserver to debug emacs with an argument of foo.txt, and to communicate with GDB via /dev/com1. Gdbserver now waits patiently for the host GDB to communicate with it. To use a TCP connection, you could say: target> gdbserver host:2345 emacs foo.txt This says pretty much the same thing as the last example, except that we are going to communicate with the host GDB via TCP. The `host:2345' argument means that we are expecting to see a TCP connection from `host' to local TCP port 2345. (Currently, the `host' part is ignored.) You can choose any number you want for the port number as long as it does not conflict with any existing TCP ports on the target system. This same port number must be used in the host GDBs `target remote' command, which will be described shortly. Note that if you chose a port number that conflicts with another ser‐ vice, gdbserver will print an error message and exit. On some targets, gdbserver can also attach to running programs. This is accomplished via the --attach argument. The syn‐ tax is: target> gdbserver COMM --attach PID PID is the process ID of a currently running process. It isn't necessary to point gdbserver at a binary for the running process. Usage (host side): You need an unstripped copy of the target program on your host system, since GDB needs to examine it's symbol tables and such. Start up GDB as you normally would, with the target program as the first argument. (You may need to use the --baud option if the serial line is running at anything except 9600 baud.) Ie: `gdb TARGET-PROG', or `gdb --baud BAUD TARGET- PROG'. After that, the only new command you need to know about is `target remote'. It's argument is either a device name (usually a serial device, like `/dev/ttyb'), or a HOST:PORT descriptor. For example: (gdb) target remote /dev/ttyb communicates with the server via serial line /dev/ttyb, and: (gdb) target remote the-target:2345 communicates via a TCP connection to port 2345 on host `the-target', where you previously started up gdbserver with the same port number. Note that for TCP connections, you must start up gdbserver prior to using the `target remote' command, (gdb) target remote /dev/ttyb communicates with the server via serial line /dev/ttyb, and: (gdb) target remote the-target:2345 communicates via a TCP connection to port 2345 on host `the-target', where you previously started up gdbserver with the same port number. Note that for TCP connections, you must start up gdbserver prior to using the `target remote' command, otherwise you may get an error that looks something like `Connection refused'. OPTIONS You have to supply the name of the program to debug and the tty to communicate on; the remote GDB will do everything else. Any remaining arguments will be passed to the program verbatim.
从实际的使用情况来看,上面gdbserver的使用文档中关于宿主机方面(Usage (host side))的阐述(仔细理解一下红色部分)似乎有误。
实际实验中,假如按照帮助文档中所说的,宿主机方面也需要有一个运行于目标机上的程序副本(You need an unstripped copy of the target program on your host system, since GDB needs to examine it’s symbol tables and such. ),并且以
arm-linux-gdb PROG
(arm-linux-gdb是宿主机上的交叉调试器名称,这里假定调试的是ARM开发板上的程序)的方式启动交叉调试器,然后使用
target remote 远程连接设备(串口设备或IP地址+端口)
命令建立连接。然而之后的调试会出现问题,而且这问题会让人混淆这程序调试究竟是调试宿主机这边的程序副本还是目标机上的程序副本。如以下图1至图4所示,目标板上的程序能正常运行并正确退出,然而arm-linux-gdb会提示缺失相应的库文件或者一些文件的格式无法识别,而这些库文件在目标机系统上的相应目录下都是存在的。提示文件格式无法识别是因为arm-linux-gdb在调试PROG程序时需要加载ARM体系结构的库文件,而这些库文件在宿主机系统上有同名的库文件(因而不会提示库文件找不到),只是体系结构是PC机的架构,所以会提示文件格式无法识别错误。