Chinaunix首页 | 论坛 | 博客
  • 博客访问: 504119
  • 博文数量: 119
  • 博客积分: 5054
  • 博客等级: 大校
  • 技术积分: 1305
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-03 13:13
文章分类

全部博文(119)

文章存档

2011年(4)

2010年(115)

我的朋友

分类: 嵌入式

2010-04-09 13:04:36

主要摘自《嵌入式linux应用程序开发详解》——华清远见

嵌入式软件经过编译和链接后即进入调试阶段,调试是软件开发过程中必不可少的一个环节,嵌入式软件开发过程中的交叉调试与通用软件开发过程中的调试方式有很大的差别。在常见软件开发中,调试器与被调试的程序往往运行在同一台计算机上,调试器是一个单独运行着的进程,它通过操作系统提供的调试接口来控制被调试的进程。而在嵌入式软件开发中,调试时采用的是在宿主机和目标机之间进行的交叉调试,调试器仍然运行在宿主机的通用操作系统之上,但被调试的进程却是运行在基于特定硬件平台的嵌入式操作系统中,调试器和被调试进程通过串口或者网络进行通信,调试器可以控制、访问被调试进程,读取被调试进程的当前状态,并能够改变被调试进程的运行状态。

嵌入式系统的交叉调试有多种方法,主要可分为软件方式和硬件方式两种。它们一般都具有如下一些典型特点。

  • 调试器和被调试进程运行在不同的机器上,调试器运行在 PC 机或者工作站上(宿主机),而被调试的进程则运行在各种专业调试板上(目标机)。
  • 调试器通过某种通信方式(串口、并口、网络、JTAG 等)控制被调试进程。
  • 在目标机上一般会具备某种形式的调试代理,它负责与调试器共同配合完成对目标机上运行着的进程的调试。这种调试代理可能是某些支持调试功能的硬件设备,也可能是某些专门的调试软件(如 gdbserver)。
  • 目标机可能是某种形式的系统仿真器,通过在宿主机上运行目标机的仿真软件,整个调试过程可以在一台计算机上运行。此时物理上虽然只有一台计算机,但逻辑上仍然存在着宿主机和目标机的区别。

下面主要介绍一下软件调试:
软件方式调试主要是通过插入调试桩的方式来进行的。调试桩方式进行调试是通过目标操作系统和调试器内分别加入某些功能模块,二者互通信息来进行调试。该方式的典型调试器有 Gdb 调试器。GDB 的交叉调试器分为 GdbServer 和 GdbClient,其中的 GdbServer 就作为调试桩安装在目标板上,GdbClient 就是驻于本地的 Gdb 调试器。它们的调试原理图如图4.19所示。



Gdb 调试桩的工作流程:

  • 首先,建立调试器(本地 Gdb)与目标操作系统的通信连接,可通过串口、网卡、并口等多种方式。
  • 然后,在目标机上开启 Gdbserver 进程,并监听对应端口。
  • 在宿主机上运行调试器 Gdb,这时,Gdb 就会自动寻找远端的通信进程,也就是 Gdbserver 的所在进程。
  • 在宿主机上的 Gdb 通过 Gdbserver 请求对目标机上的程序发出控制命令。这时,Gdbserver 将请求转化为对程序的地址空间或目标平台的某些寄存器的访问,这对于没有虚拟存储器的简单的嵌入式操作系统而言,是十分容易的。
  • Gdbserver 把目标操作系统的所有异常处理转向通信模块,并告知宿主机上 Gdb 当前的异常。
  • 宿主机上的 Gdb 向用户显示被调试程序产生了哪一类异常。

这样就完成了调试的整个过程。这个方案的实质是用软件接管目标机的全部异常处理及部分中断处理,并在其中插入调试端口通信模块,与主机的调试器进行交互。但是它只能在目标机系统初始化完毕、调试通信端口初始化完成后才能起作用,因此,一般只能用于调试
运行于目标操作系统之上的应用程序,而不宜用来调试目标操作系统的内核代码及启动代码。

gdbserver的使用

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机的架构,所以会提示文件格式无法识别错误。

 


所以,我个人认为正确的使用方法是:宿主机方面直接启动交叉调试器,并不需要接受被调试的程序作为参数启动,启动调试器后建立宿主机和目标板之间的连接方法相同。根据上述的交叉调试原理中GDB调试桩的工作流程,似乎也是这么个意思。事实胜于雄辩,不加被调试的程序名作为参数启动调试器交叉调试运行于目标系统上的程序(进程),则不会再出现上面截图所反映的错误了。


阅读(4490) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

love_wisdom2012-11-05 13:43:14

请教一下,如果写一个不是本地平台的程序,这个程序直接在机器上模拟运行,不再另外的机器上运行,该怎么调试?