建立嵌入式gdb調試環境

建立嵌入式gdb調試環境

 

.下載gdb-7.1.tar.gz源代碼

phil@ubuntu-embedded:~/gdb-7.1$ wget http://ftp.gnu.org/gnu/gdb/gdb-7.1.tar.gz

 

二.編譯 GDB

#tar zxvf gdb-7.1.tar.gz

 

2.1 編譯GDB Client

phil@ubuntu-embedded:~/gdb-7.1$ cd gdb-7.1/

phil@ubuntu-embedded:~/gdb-7.1$ ./configure --target=arm-linux --prerix=`pwd`/rls

phil@ubuntu-embedded:~/gdb-7.1$ make

phil@ubuntu-embedded:~/gdb-7.1$ make install

phil@ubuntu-embedded:~/gdb-7.1$ ls rls/bin/

arm-linux-gdb  arm-linux-gdbtui  arm-linux-run

phil@ubuntu-embedded:~/gdb-7.1$ file rls/bin/arm-linux-gdb

rls/bin/arm-linux-gdb: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped 

 

2.2 編譯GDB Server

#cd ./gdb/gdbserver

#./configure --target=arm-linux --host=arm-linux

 

三.實戰調試

1.編輯文件

# vi gdbtest.c

#include <stdio.h>

 

int

func(int n){

     int   sum=0, i;

     for (i=0; i<n; i++){

         sum += i;

     }

     return sum;

 }

 

 int

 main(void)

 {

    int   i;

    long result = 0;

    for (i=0; i<=100; i++){

        result += i;

    }

 

    printf("result[1-100] = %d /n", result);

    printf("resutl[1-225] = %d /n", func(255));

 

    return 0;

}

# arm-linux-gcc -g gdbtest.c -o gdbtest         // 交叉編譯

2.下載文件到目標板: gdbtestgdbserver

假設 host pc ip:192.168.1.45

     board   ip:192.168.1.180   

將文件拷貝到目標板上:

先將gdbtestgdbserver兩個文件拷貝到主機的/tftpboot目錄下

在目標板的Linux中運行:

#mount 192.168.1.108:/tftpboot /mnt/nfs

#cd /mnt/nfs

#ls

看是否有gdbtestgdbserver兩個文件。

3.運行調試

client board

#./gdbserver 192.168.1.45:1234 gdbtest  // 目標板上運行gdbtest 監聽端口1234

 

host pc

#cd /usr/local/arm-gdb/bin/

#copy gdbtest /usr/local/arm-gdb/bin/   // 將前面編譯的文件gdbtest拷貝到此目錄

#./arm-linux-gdb gdbtest

(gdb)target remote 192.168.1.180:1234   // 連接到開發板 成功後就可以進行調試             

(gdb)list   or l

(gdb)break func

(gdb)break 22

(gdb)info br   

(gdb)continue   or c    //記住這裏不是用run, 因爲程序已在Target Board上面由gdbserver啓動了。結果輸出是在Target Board

 

(gdb)next   or n

(gdb)print or p    result 

(gdb) finish        // 跳出func函數

(gdb) next

(gdb) quit

建立連接後進行gdb遠程調試和gdb本地調試方法相同

 

 說明 
1)目標機上的被調試程序gdbtest, 與主機上的程序gdbtest, 是相同的程序, 但位置不一樣,並非是用網絡共享的同一個位置的同一個文件, 一個在目標機上 ,一個在主機上, 沒有關係

 

 

Remote cross-target debugging with GDB and GDBserver

In theory, GDB, the GNU debugger, can ease the chore of debugging applications running on a Linux-based embedded system. In practice, setting up GDB for this task is a bit of a challenge; it takes some work, and there are some technical hurdles to overcome. However, the benefits of having a way to methodically debug a program instead of guessing what's wrong with it far outweigh the effort involved. Here are some tips for easing the difficulties.

Rather than run a full-blown instance of GDB on the target platform, you can use GDBserver, a program that lets you run GDB on a different machine than the one on which your program is running. The advantage of using GDBserver is that it needs just a fraction of the target resources that GDB consumes, because it implements only the low-level functionality of the debugger -- namely setting breakpoints and accessing the target processor registers and read/write application memory. GDBserver takes control of the application being debugged, then waits for instructions from a remote instance of GDB running on a development workstation.

Typically, the development workstation has a different processor (say, an i686 class processor) than the target platform (which may be ARM, PowerPC, or something else). This means you can't simply use the GDB executable that's installed on the workstation -- you want a cross-targetdebugger. In other words, you have to custom-build GDB from source code.

Building GDB

The following example uses a 7450 PowerPC as the target processor.

Before you begin, you need a communication interface between the PC running GDB and the target platform: either a serial link or, preferably, an Ethernet network connection. You also need a cross-target toolchain: a GNU C compiler (together with a C run-time library and binary utilities, a.k.a. binutils) that runs on the development workstation and generates executables for the target processor. You will build two sets of binaries from the GDB source code:

§                 cross-target -- where the host is the development workstation and the target is the target processor

§                 native -- where both host and target are the target processor

First download the GDB source code compressed archive, and unpack it:

  mkdir -p ~/work/cross/gdb/downloads
  cd ~/work/cross/gdb/downloads
  wget http://ftp.gnu.org/gnu/gdb/gdb-6.7.1.tar.bz2
  cd ..
  tar xvjf downloads/gdb-6.7.1.tar.bz2

The GDB source package uses the GNU build system, where generating binaries is usually just a few commands away (./configure ; make ; make install). But in our case it's a bit tricky: we intend to build binaries for two different host processors, and install the binaries at different locations. So we'll build the binaries in their own directories, instead of the directory into which we unpacked the source package. Furthermore, we'll use the configure script's command-line options to specify the target and host processors, and the installation directory prefix.

To build the cross-target binaries, specify the target architecture with the --target option. The architecture identifier (here powerpc-7450-linux-gnu) is the prefix of all the cross-toolchain binaries (here the cross compiler binary is powerpc-7450-linux-gnu-gcc).

  mkdir -p ~/work/cross/gdb/build/host_x86
  cd ~/work/cross/gdb/build/host_x86
  ../../gdb-6.7.1/configure --prefix=/opt/gdb/powerpc-7450-linux-gnu/cross --target=powerpc-7450-linux-gnu
  make
  make install

Building the target-native binaries is trickier. For one thing you need to specify the host architecture (same as the target architecture powerpc-7450-linux-gnu). Another issue is missing libraries -- some libraries may not be available in the cross-toolchain, and must be built before you try to build a target-native GDB. This example shows how to succeed when you find a target-native termcap library is missing (cross building is somewhat different here -- use ./configure --help when in doubt):

  cd ~/work/cross/gdb/downloads
  wget ftp://ftp.gnu.org/gnu/termcap/termcap-1.3.1.tar.gz
  cd ..
  tar xvzf downloads/termcap-1.3.1.tar.gz
  mkdir -p ~/work/cross/gdb/build/termcap
  cd ~/work/cross/gdb/build/termcap
  
  export CC=powerpc-7450-linux-gnu-gcc
  export RANLIB=powerpc-7450-linux-gnu-ranlib
  ../../termcap-1.3.1/configure --host=powerpc-7450-linux-gnu --prefix=$HOME/work/cross/termcap
  make
  make install

One last issue to consider is whether the binaries should be statically linked. This is required if the target platform is missing some of the shared libraries that GDB and GDBserver depend on for normal operation, but the resulting executables are much larger than dynamically linked ones. You can specify static linking by adding the option -static to the LDFLAGS environment variable before running configure. Any additional library should also be specified in both LDFLAGS and CPPFLAGS, as follows:

  export LDFLAGS="-static -L$HOME/work/cross/termcap/lib"
  export CPPFLAGS="-I$HOME/work/cross/termcap/include"
  ../../gdb-6.7.1/configure --prefix=/opt/gdb/powerpc-7450-linux-gnu/native --host=powerpc-7450-linux-gnu --target=powerpc-7450-linux-gnu
  make
  make install

The GNU linker will issue some warnings during the build process. Using some functions (for instance dlopen, gethostbyname, and a few more) in statically linked applications requires at runtime the shared libraries from the GNU C runtime library version used for linking. You may have to install these libraries on the target platform.

Once you've generated the GDBserver executable, copy it to the target platform. You can save some storage space by stripping all the debug information from it first, using the powerpc-7450-linux-gnu-strip utility.

Adapting the build procedure for a different target processor should only be a matter of using a different architecture identifier.

Usage

To facilitate debugging, you must compile an application with debug information by providing the -g command line option to the compiler/linker. The resulting executable file may be too big to fit into the storage space available on the target platform, so before moving it there you can strip the debug information from a copy of it using powerpc-7450-linux-gnu-strip, and place the stripped copy on the target platform. The stripped version is to be run with GDBserver on the target platform, and the non-stripped copy is to be loaded into GDB on the development workstation.

Remote debugging is rather straightforward: on the target platform, launch the application with GDBserver, while specifying the host and port for listening to an incoming TCP connection:

  gdbserver HOST:PORT PROG [ARGS ...]

On the development workstation, launch the cross-target GDB:

  powerpc-7450-linux-gnu-gdb PROG

Be sure to specify the non-stripped executable. At the GDB console, type:

  target remote HOST:PORT
  break main
  continue

These commands will connect GDB to the GDBserver running on the target platform, set a breakpoint at the start of the program, and let it run until it reaches that first breakpoint.

You can also attach GDBserver to a process that's already running:

  gdbserver HOST:PORT --attach PID

The process is then stopped, and you can then debug it with a remote GDB.

GDB commands work as expected while debugging a remote application, with a few exceptions -- most notably, the run command isn't used, since the program is already running when you start the debug session. Another quirk is that if the program is allowed to continue until it exits, then the remote GDBserver will exit too, and the remote session will terminate.

Setting up a working remote debugging environment may seem like too much of hassle to some -- "after all, nothing beats a well placed printf." But with GDB you can both trace and modify code and data flow, and otherwise analyse the behaviour of your code, without explicitly changing any of it. It doesn't magically solve bugs, but it sure helps.

 


Using the gdbserver program

gdbserver is a control program for Unix-like systems, which allows you to connect your program with a remote GDB via target remote---but without linking in the usual debugging stub.

gdbserver is not a complete replacement for the debugging stubs, because it requires essentially the same operating-system facilities that GDB itself does. In fact, a system that can run gdbserver to connect to a remote GDB could also run GDB locally! gdbserver is sometimes useful nevertheless, because it is a much smaller program than GDB itself. It is also easier to port than all of GDB, so you may be able to get started more quickly on a new system by using gdbserver. Finally, if you develop code for real-time systems, you may find that the tradeoffs involved in real-time operation make it more convenient to do as much development work as possible on another system, for example by cross-compiling. You can use gdbserver to make a similar choice for debugging.

GDB and gdbserver communicate via either a serial line or a TCP connection, using the standard GDB remote serial protocol.

On the target machine,

you need to have a copy of the program you want to debug. gdbserver does not need your program's symbol table, so you can strip the program if necessary to save space. GDB on the host system does all the symbol handling.

To use the server, you must tell it how to communicate with GDB; the name of your program; and the arguments for your program. The syntax is:

target> gdbserver comm program [ args ... ]

comm is either a device name (to use a serial line) or a TCP hostname and portnumber. For example, to debug Emacs with the argument `foo.txt' and communicate with GDB over the serial port`/dev/com1':

target> gdbserver /dev/com1 emacs foo.txt

gdbserver waits passively for the host GDB to communicate with it.

To use a TCP connection instead of a serial line:

target> gdbserver host:2345 emacs foo.txt

The only difference from the previous example is the first argument, specifying that you are communicating with the host GDB via TCP. The `host:2345' argument means that gdbserver is to expect a TCP connection from machine `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 TCP ports already in use on the target system (for example, 23 is reserved for telnet).(3) You must use the same port number with the host GDB target remote command.

On the GDB host machine,

you need an unstripped copy of your program, since GDB needs symbols and debugging information. Start up GDB as usual, using the name of the local copy of your program as the first argument. (You may also need the `--baud' option if the serial line is running at anything other than 9600 bps.) After that, use target remote to establish communications with gdbserver. Its argument is either a device name (usually a serial device, like `/dev/ttyb'), or a TCP port descriptor in the form host:PORT. 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'. For TCP connections, you must start up gdbserver prior to using the target remote command. Otherwise you may get an error whose text depends on the host system, but which usually looks something like `Connection refused'.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章