嵌入式GDB调试Linux C程序或交叉编译(开发板)

更新日志:

v1.2 2024年6月24日19:59:19 基本文档编写 2024年7月2日发布于博客园

简介

gdb工具是 GNU项目调试器,基于命令行。和其他的调试器一样,我们可以使用 gdb来一行行的运行程序、单步执行、跳入 /跳出函数、设置断点、查看变量等等,它是 UNIX/LINUX操作系统下强大的程序调试工具。 gdb支持多种语言,包括 Ada、汇编、 C/C++、 D、 Fortran、 GO、Objective-C、 OpenCL、 Modula-2、 Pascal和 Rust。关于 gdb更多详细的信息请到 gdb官网查阅,gdb官网地址为: www.gnu.org。
一般的桌面 Linux系统,比如 ubuntu、 centos等,我们可以直接运行 gdb来调试程序。但是嵌入式中芯片性能一般比较弱,所以直接在嵌入式系统中运行 gdb不太现实 (性能强大的嵌入式芯片可以这么做 )。嵌入式系统中一般在 PC端运行 gdb工具,源码也是在 PC端,源码应的可执行文件放到开发板中运行。为此我们需要在开发板中运行 gdbserver,通过网络与 PC端的 gdb进行通信。因此要想在 PC上通过 gdb调试嵌入式程序,那么需要两个东西: gdb和gdbserver,其中 gdb是运行在 PC上的, gdbserver需要我们移植到开发板上。

开始使用

开发板要和上位机处于同一局域网!!

开发板要和上位机处于同一局域网!!

开发板要和上位机处于同一局域网!!

重要的事情说三遍!

电脑端

准备

安装gdb

在root用户权限下:

root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get update
root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get install gdb 
Do you want to continue? [Y/n] y

1.编译带调试信息的可执行文件

使用编译命令 -g 例如:

-g选项的作用是:在可执行文件中加入源码信息,比如:可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件都嵌入到可执行文件中,而是在调试时必须保证gdb能找到源文件。

cc client.c cJSON.c myJSON.c base64.c -g -o client.out  -pthread

2.进入gdb

gdb client.out

这时候gdb环境准备就绪, 会有欢迎界面, 按一下回车键, 开始进入命令输入

3.启动程序

start

这时候程序启动,但等待你的下一步操作, 可以设置断点等

常用命令

在start以后

设置断点:

b 124 #在第124行设置断点, 然后继续
c #让程序运行到设置的断点 124 行停下. 这里的行数是你的main.c的行数
n #单步运行: 让程序一次运行一行, 注意不会入子函数模块!! 只会显示函数运行结果,例如第124行是调用函数, 则应该c 124, 让程序在124停止

进入函数

step #在上面的设置断点到 124行的函数调用时 , 进入到124行的函数内部
n #继续在函数内部按行执行, 是可以继续设置断点的. 

打印数值

display count#display可以将变量count添加到监听队列, 监听队列的值会被显示打印出来
undisplay 3#将监听队列中的第三号成员移除队列

结束

quit #退出gdb! !!!!注意不可以ctrl+C结束程序, 会导致异常!!!!! 会导致异常!!!!

常用命令

l

是L的小写

l命令 (list)用于列出所有程序源码,输入“ l”

输入“ l”命令以后就打印出了调试程序的所有源码,如果源码没有打印完的话就重复按下“ l”命令,或者按下回车键, gdb调试工具中回车键表示重复上一个命令!

回车键

重复上一个命令

b

b命令 (break)用于设置断点,也可以用缩写“ b”,后面可以跟具体的函数或者行号,比如break main”表示在 main函数处设置断点,“ break 11”在第 11行设置断点。

b 11 #在第 11行设置断点
b main #在 main函数处设置断点

C

命令用于运行到断点 处 ,输入 c命令程序就会运行,直到下一个断点处(该断点只会作用一次). 再次c就会继续往下, 若没有断点就会继续执行, 直到程序结束.

S

s命令 (step)是单步运行执行,此函数会进入到函数里面。

n

n命令 (next)也是单步运行,但是 n命令不会进入到函数里面。

p

p命令 (print)用于打印某个变量值。

q

q命令 (quit)用于退出调试,开发板上的 gdbserver也会停止。

参考文档

1、安装gdb。

在root用户权限下:

root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get update
......
......
......
root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get install gdb 
......
......
......
Do you want to continue? [Y/n] y
......
......
......
root@iZ2zeeailqvwws5dcuivdbZ:~# 

安装好gdb了。

2、gdb的简单使用。

用root权限的Terminal(或一般权限的Terminal)的vi编辑器编写一个C程序a.c:

1 #include <stdio.h>
2 
3 int main()
4 {
5   int a = 1;
6   int b = a;
7 
8   printf("a = %d, b =%d\n", a, b);
9 
10   return 0;
11 }

(1) 在可执行文件中加入源码信息

这个过程通过gcc来完成:

gcc –o a a.c -g

-o选项的作用是:对命令输出结果进行导入操作,这里是把gcc –o a a.c -g的操作结果输出到文件a(文件名可以自定义)中进行保存。

-g选项的作用是:在可执行文件中加入源码信息,比如:可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件都嵌入到可执行文件中,而是在调试时必须保证gdb能找到源文件。

(2) 进入gdb

root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gcc -o a a.c -g
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a...done.
(gdb) 

如下图所示:

gdb提供一个类似Shell的命令行环境,上面的(gdb)就是提示符,在提示符后面输入gdb的相应命令就可以实现其对应的功能。

(3) gdb调试常用命令

[1] start

  用start命令开始执行程序:

(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) 

  gdb提示准备执行a.c程序的第六行代码。然后继续用(gdb)提示需要输入的命令。

[2] 单步执行(n)

(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) n
6           int b = a;
(gdb) n
8           printf("a = %d, b = %d\n", a, b);
(gdb) n
a = 1, b = 1
9           return 0;
(gdb) quit
A debugging session is active.

   Inferior 1 [process 22935] will be killed.

Quit anyway? (y or n) y
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# 

  在start命令后,每输入一个n就能够单步执行一条语句(输入一个命令后,直接回车表示最近输入命令的含义)。当程序执行完时,可以输入quit命令来退出gdb模式。

[3] gdb断点调试

  [ breakpoint,*continue和*display ]

(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) b 8
Breakpoint 2 at 0x40053b: file a.c, line 8.
(gdb) c
Continuing.

Breakpoint 2, main () at a.c:8
8           printf("a = %d, b = %d\n", a, b);
(gdb) display b
1: b = 1
(gdb) n
a = 1, b = 1
9           return 0;
1: b = 1
(gdb) 
10      }
1: b = 1
(gdb) quit
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# 

  gdb a会进入a可执行程序的gdb模式,start命令就使程序准备运行程序中的第一条语句。b 8是breakpoint 8的简写(breakpoint的参数也可以以是某个函数名,表示在此函数处设置一个断点),表示在程序第八行设置一个断点。c是continue的缩写,表示继续运行程序,程序会在设置断点处停下来。displayb表示将b的值显示出来(undisplay取消对变量的跟踪),然后再输入单步调试命令n(next)就可以使程序继续运行。

  可见断点有助于快速跳过没有问题的代码,然后在有问题的代码上慢慢走慢慢分析,“断点加单步”是使用调试器的基本方法。至于应该在哪里设置断点,怎么知道哪些代码可以跳过,而哪些代码要慢慢走,也要通过对错误现象的分析和假设来确定,以前我们用printf打印中间结果时,也要分析应该在哪里插入printf,打印哪些中间结果,调试的基本思路是一样的。

  [4]*info*

  一次调试可以设置多个断点,用info命令可以查看已经设置的断点:

root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a...done.
(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) b 7
Breakpoint 2 at 0x40053b: file a.c, line 7.
(gdb) b 8
Note: breakpoint 2 also set at pc 0x40053b.
Breakpoint 3 at 0x40053b: file a.c, line 8.
(gdb) i breakpoints 
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040053b in main at a.c:7
3       breakpoint     keep y   0x000000000040053b in main at a.c:8
(gdb) 

  [5]*delete*

  每个断点都有一个编号(有的断点行数不一样,但地址却一样,有的地方不能够设置断点或者说与上一个设置的断点等效),可以用编号指定删除某个断点。

......(gdb) b 7
Breakpoint 2 at 0x40053b: file a.c, line 7.
(gdb) b 8
Note: breakpoint 2 also set at pc 0x40053b.
Breakpoint 3 at 0x40053b: file a.c, line 8.
(gdb) i breakpoints 
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040053b in main at a.c:7
3       breakpoint     keep y   0x000000000040053b in main at a.c:8
(gdb) delete 3
(gdb) i breakpoints 
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x000000000040053b in main at a.c:7
(gdb) 

  有时候一个断点暂时不用可以禁用掉而不必删除,这样以后想用的时候可以直接启用,而不必重新从代码里找应该在哪一行设断点,这个过程用 disable 和 enable 来完成。

  [6]*条件断点 (break 和run)*

  gdb的断点功能非常灵活,还可以设置断点在满足某个条件时才激活,例如:

......//先把其余的断点删掉。(gdb) b 9 if a == 2
Breakpoint 5 at 0x400552: file a.c, line 9.
(gdb) i breakpoints 
Num     Type           Disp Enb Address            What
5       breakpoint     keep y   0x0000000000400552 in main at a.c:9
   stop only if a == 2
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/2/02/a 
a = 1, b = 1
[Inferior 1 (process 22968) exited normally]
(gdb) 

  r表示从头开始运行程序,在a==2的条件下中断才有效。a不等于2,所以中断无效。  

[7] gdb的观察点(watch 和c)

  断点是当程序执行到某一代码行时中断,而观察点是当程序访问某个存储单元时中断,如果我们不知道某个存储单元是在哪里被改动的,这时候观察点尤其有用。

root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a...done.
(gdb) start
Temporary breakpoint 1 at 0x40052e: file a.c, line 5.
Starting program: /root/2/02/a 

Temporary breakpoint 1, main () at a.c:5
5           int a = 1;
(gdb) watch b
Hardware watchpoint 2: b
(gdb) c
Continuing.

Hardware watchpoint 2: b

Old value = 0
New value = 1
main () at a.c:8
8           printf("a = %d, b = %d\n", a, b);
(gdb) 

  程序执行到b存储单元,将此执行单元执行前后的值都显示出来。

[8] 段错误

  如果程序运行时出现段错误,用gdb可以很容易定位到究竟是哪一行引发的段错误。在gdb中运行,遇到段错误会自动停下来,这时可以用命令查看当前执行到哪一行代码了。

  gdb显示段错误出现在 _IO_vfscanf 函数中,用bt命令可以看到是哪一个函数调用了它。

[9] gdb基本命令

  gdb有许多有用的命令如list(显示源代码),这样就可以结合源码与调试信息更好的进行调试。将gdb常用命令摘抄如下表:

命令 描述
backtrace(bt) 查看各级函数调用及参数
finish 连续运行到当前函数返回为止,然后停下来等待命令
frame(f) 帧编号 选择栈帧
info(i) locals 查看当前栈帧局部变量的值
list(l) 列出源代码,接着上次的位置往下列,每次列十行
list 行号 列出第几行开始的源代码
list 函数名 列出某个函数的源代码
next(n) 执行下一行语句
print(p) 打印表达式的值,通过表达式的值可以修改变量的值或者调用函数
quit(q) 退出gdb调试环境
set var 修改变量的值
start 开始执行程序,停在main函数第一行语句前面等待命令
step(s) 执行下一行语句,如果有函数则进入到函数中
break(b) 行号 在某一行设置断点
break 函数名 在某个函数开头设置断点
break(b)… if… 设置条件断点
continue(c) 从当前位置开始连续运行程序
delete breakpoints 断点号 删掉此号的断点
display 变量名 跟踪查看某个变量,每次停下来都显示它的值
disable breakpoints 断点号 禁用此断点
enable 断点号 启用此断点
info(i) breakpoints 查看当前设置了哪些断点
run(r) 从头开始连续运行程序
undisplay 跟踪显示行号 取消跟踪显示
watch 设置观察点
info(i) watchpoints 查看当前设置了哪些观察点
x 从某个位置开始打印存储单元的内容,全部当成字节来看,而不区分哪个字节属于哪个变量
disassemble 反汇编当前函数或者指定的函数,单独用disassemble命令是反汇编当前函数,如果disassemble命令后面跟函数名或地址则反汇编指定的函数。
si 可以一条指令一条指令地单步调试。
info registers 可以显示所有寄存器的当前值。在gdb中表示寄存器名时前面要加个$,例如p $esp可以打印esp寄存器的值。
set follow-fork-mode child/parent 设置gdb在fork之后跟踪子进程/父进程
set args 'command-line' 给执行的程序传命令行参数
s(stepin) 进入子函数

开发板移植-自行编译(作废)

适用于编译器没有自带gdb, 需要编译.

2024年6月24日: 尝试编译失败, 使用粤嵌的5.4.0交叉编译器, 无法生成gdb, 怀疑是编译器不完全, 解决方法: 更换编译器.

获取 gdb和 gdbserver源码

开发板配套默认的编译器没有gdb因此需要自己编译

首先到 gdb官网上获取源码,地址为 https://www.gnu.org/software/gdb/download/在笔者写本教程的时候,最新的 gdb源码 版本 为 9.1。已经放到了开发板光盘中,路径为: 1、例程源码->7、第三方库源码 -> gdb-9.1.tar.gz。将 gdb源码发送到 ubuntu中 中并解压,命令如下:

Index of /pub/gdb/releases (sourceware.org)

以root账户运行:

cd /root
mkdir gdb 
mkdir /DevelopmentTool/gdb#存放编译后可运行的gdb
#将文件放入 gdb文件夹中,临时存放
root@yuyi-machine:~/gdb# tar -vxzf gdb-9.1.tar.gz//解压 gdb源码
root@yuyi-machine:~/gdb# ls
gdb-9.1  gdb-9.1.tar.gz

解压完成以后就会得到一个名为 gdb-9.1的文件夹,此文件夹就是 gdb和 gdbserver源码,其中 gdb-9.1/gdb/gdbserver目录就是 gdbserver源码。

编译 gdb

1、编译 gdb
首先编译 gdb gdb是运行在 PC端的程序, gdb编译的时候需要进行配置,配置项如下:

--target 目标机交叉编译器前缀,也就是你所使用的交叉编译器前缀,比如在本教程中就设置为 arm-linux-gnueabihf。
--host 指定编译后的程序在哪里运行,编译 gdb的时候就需用设置,因为我们是需要在 PC上运行的,编译 gdbserver的时候就要设置为 arm-linux。
--prefix 指定安装目录。
创建一个名为“gdb”的文件夹,用来保存编译后的 gdb和 gdbserver,路径自行选择。 gdb编译比较奇葩!使用如下命令配置并编译 gdb: 


cd gdb-9.1/ 	//进入 gdb源码目录
mkdir build 	//在 gdb源码下新建 build目录, gdb编译比较奇葩!不能直接在 gdb源
				//码目录下进行配置和编译,必须新建一个文件夹,然后在此文件夹下配置和编译,切记!
cd build //进入到刚刚创建的 build目录下
../configure --target=arm-linux-gnueabihf --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/gdb 
				//配置 gdb。配置完成以后会在 build目录下生成 Makefile文件。
make //编译
make install //安装

运行实例:

root@yuyi-machine:~/gdb# ls
gdb-9.1  gdb-9.1.tar.gz
root@yuyi-machine:~/gdb# cd gdb-9.1/
root@yuyi-machine:~/gdb/gdb-9.1# mkdir build
root@yuyi-machine:~/gdb/gdb-9.1# cd build
root@yuyi-machine:~/gdb/gdb-9.1/build# ../configure --target=arm-linux --prefix=/DevelopmentTool/gdb
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking target system type... arm-unknown-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
********
********
make 
make[4]: *** [Makefile:490: gdb.info] Error 127
make[4]: Leaving directory '/root/gdb/gdb-9.1/build/gdb/doc'
make[3]: *** [Makefile:2006: subdir_do] Error 1
make[3]: Leaving directory '/root/gdb/gdb-9.1/build/gdb'
make[2]: *** [Makefile:1651: all] Error 2
make[2]: Leaving directory '/root/gdb/gdb-9.1/build/gdb'
make[1]: *** [Makefile:9564: all-gdb] Error 2
make[1]: Leaving directory '/root/gdb/gdb-9.1/build'
make: *** [Makefile:852: all] Error 2
root@yuyi-machine:~/gdb/gdb-9.1/build#
########################这里之后就报错了, 具体不清楚,

make install



root@yuyi-machine:~/gdb/gdb-9.1/build# cd /DevelopmentTool/gdb/
root@yuyi-machine:/DevelopmentTool/gdb# ls
bin  lib  share

编译完成以后 PC端运行的 gdb工具就会安装到 gdb/bin目录下,名字为 arm-linux-gnueabihf-gdb,如图 B3.2.2.1所示:

########################这里之后就报错了, 具体不清楚,

开发板移植-自行编译(成功)

下载可用的编译器

下载

Linaro Releases

板子应该下载x86_64的版本, 因为开发平台是64位的linux. 应该不要下载带h的, h表示硬浮点, 因为粤嵌的板子的Linux文件系统中的库都是使用软浮点模式编译的.

官方给的5.4.0版本不完全, 使用很多库会报错! 要修改的有很多. 故推荐5.4.1

安装

sudo apt-get install lsb-core lib32stdc++6 #安装其它的库

在电脑的Linux系统中切换为root用户

su - #切换root
cd /
mkdir /DevelopmentTool/ #创建文件夹
# 然后将 下载好的 gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi.tar.xz 上传到其中
tar -vxf gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi.tar.xz #解压
cd /etc/profile.d #进入全局脚本文件夹
touch IoT_development.sh #创建自定义脚本文件 
chmod 644 IoT_development.sh
vim IoT_development.sh
# 修改环境变量, 加入下面的内容即可
export PATH=/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/bin:$PATH
# 重启系统或 
source ./IoT_development.sh
# 查看版本号  如果交叉编译器安装正确的话就会显示版本号,如图
arm-linux-gnueabi-gcc -v
# 若没有生效, 需要每个用户在终端手动运行下面命令, 或设置另一个全局变量脚本文件
echo "export PATH=/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/bin:$PATH"  >>  ~/.bashrc
source ~/.bashrc
arm-linux-gnueabi-gcc -v

使用

# 终端直接编译
arm-linux-gnueabi-gcc main.c -o demo.out
# Makefile编写
CC = arm-linux-gnueabi-gcc

若有多个不同版本的交叉编译链, 使用时使用完整的名称即可.

若有需要,程序相关的依赖环境,需要自己补上.

GDB移植到开发板

到了这一步, 编译器已经可以用gdb, 但是开发板不支持

查看编译器笔记, 下载新交叉编译器gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi.tar.xz

编译可调试的程序

使用 arm-linux-gnueabi-gcc交叉编译 demo.c文件,要想调试程序,那么编译的时候必须加上“ “-g”选项,这样编译出来的可执行文件才

带有调试信息,这一点一定要切记!编译命令如下所示:

arm-linux-gnueabi-gcc demo.c -o demo.out -g //编译测试程序,注意 -g选项

编译完成以后将得到的 demo.out可执行文件发送到开发板中。

gdb+gdbserver调试程序

一切准备就绪以后就可以使用 GDB进行调试了,确保 ubuntu和开发板可以进行网络通信。
开发板中输入如下命令:

下面以客户端 arm-linux-gnueabi-gcc client.c -o client.out -g -pthread 做示范

编译程序:

yuyi@yuyi-machine:~/workspace/zqingyangLib/examples/2024年6月21日_文件传输/temple$  arm-linux-gnueabi-gcc client.c -o client.out -g  -pthread 
yuyi@yuyi-machine:~/workspace/zqingyangLib/examples/2024年6月21日_文件传输/temple$ file client.out 
client.out: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=0fe128394b46c30aa29bc8c4ee4914f35b7305e4, with debug_info, not stripped

传输可执行文件到开发板

然后将文件传输到开发板,

运行程序

在开发板上输入:

gdbserver 192.168.64.202:2001 ./client.out //启动开发板上的 gdbserver
#gdbserver <上位机(调试机)的IP>:<自定义通信端口号> <要调试的可执行文件,例如./client.out>

结果

[root@GEC6818 /yuyiworkspace/tmp]#chmod 777 client.out
[root@GEC6818 /yuyiworkspace/tmp]#gdbserver 192.168.64.202:2001 ./client.out
Process ./client.out created; pid = 1516
Listening on port 2001

上位机(调试机)中输入如下命令启动 gdb调试工具:

这里的./client.out是你要调的程序在上位机的位置, 也就是两边都要有 !!!

arm-linux-gnueabi-gdb  ./client.out #这里的./client.out是你要调的程序在上位机的位置, 也就是两边都要有

结果

yuyi@yuyi-machine:~/workspace/zqingyangLib/examples/2024年6月21日_文件传输$ arm-linux-gnueabi-gdb  ./client.out
GNU gdb (Linaro_GDB-2017.01) 7.12.1.20170127-git
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=arm-linux-gnueabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...

上位机: 连接开发板

target remote 192.168.64.203:2001 #连接到开发板上
#target remote <开发板地址>:2001

连接成功以后开发板中的 gdbserver就会提示连接信息, 下面是开发板的终端输出:

[root@GEC6818 /yuyiworkspace/tmp]#gdbserver 192.168.64.202:2001 ./client.out
Process ./client.out created; pid = 1516
Listening on port 2001
Remote debugging from host 192.168.64.202

可以看出,远端调试机的 IP地址为 192.168.64.202,也就是我们的上位机地址,连接成功以后就可以在ubuntu上进行代码调试了。

下面是上位机的输出

./client.out: No such file or directory.
(gdb) target remote 192.168.64.203:2001
Remote debugging using 192.168.64.203:2001
Reading /yuyiworkspace/tmp/client.out from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /yuyiworkspace/tmp/client.out from remote target...
Reading symbols from target:/yuyiworkspace/tmp/client.out...done.
Reading /lib/ld-linux.so.3 from remote target...
Reading /lib/ld-linux.so.3 from remote target...
Reading symbols from target:/lib/ld-linux.so.3...done.
0xb6fcea80 in _start () from target:/lib/ld-linux.so.3
(gdb) 

然后可以开始使用了

VSCode+gdbserver图形化调试

gdb+gdbserver实现对嵌入式linux程序的调试,由于主机上的gdb工具是基于命令行的,因此调试起来不方便,虽然可以加一些插件,但是依旧和IDE的调试体验差很多。如何使用VSCode+gdbserver来实现图形化界面的嵌入式linux程序调试。

VSCode设置

给VScode安装远程调试插件Remote Development点击“调试添加配置然后选择C++(GDB/LLDB)选项.

若没有配置文件要点 创建 launch.json文件

选择图中的“ C++(GDB/LLDB)”,会在当前文件夹新建一个名为 launch.json”的文件,此文件会存放在 .vscode目录下,

launch.json文件内容如下所示:

{
    //需要修改的内容: ★ 。
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch", //★配置名称;显示在启动配置下拉菜单中。
            "type": "cppdbg", //配置类型。默认
            "request": "launch", //请求配置类型。可以是“启动”或“附加”。
            //program 程序可执行文件的完整路径, ${workspaceFolder}是我当前打开的文件工作路径 家目录 client.out是我要调试的程序
            "program": "${workspaceFolder}/zqingyangLib/examples/2024年6月21日_文件传输/temple/client.out", //★
            "args": [], //传递给程序的命令行参数
            "stopAtEntry": false, //可选参数。 先打断点 再运行 如果为 true,则调试程序应在目标的入口点处停止。如果传递了 processId,则不起任何作用。
            "cwd": "${workspaceFolder}/zqingyangLib/examples/2024年6月21日_文件传输/temple", //★需要调试的应用程序源码路径。main的位置
            "environment": [], //要添加到程序环境的环境变量
            "externalConsole": false, //如果为 true,则为调试对象启动控制台
            "MIMode": "gdb", //要连接到的控制台调试程序。允许的值为 "gdb"
            //miDebuggerPath ★此项需要手动添加,用于指定所使用的交叉编译器 gdb路径。
            "miDebuggerPath": "/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-gdb",
            "miDebuggerServerAddress": "192.168.64.203:2002" //★此项需要手动添加,远程 gdbserver服务器地址。开发板的地址和服务端口
        }
    ]
}

VSCode调试方法

VSCode设置好以后就可以进行调试了,首先要启动开发板上的 gdbserver,输入如下命令

gdbserver 192.168.64.202:2002 client.out

接下来在点击 VSCode上的“调试” ”->“启动调试”按钮,如图

由于是通过网络进行调试的,因此启动调试以后会有一个建立连接的过程,可能需要几秒钟,建立成功以后如上图

依赖环境搭建

LVGL-freeType字体

设置中文字体

LVGL移植使用中文字库
FreeType简介:
FreeType是一款开源的字体渲染引擎,它支持多种字体格式,包括TrueType,Type 1,OpenType依赖关系:LVGL-->FreeType-->Libpng-->zlib
which arm-linux-gcc 可以查看安装路径

第一步:把freetype和zlib中的头文件和库文件分别拷贝到ubuntu的arm-linux-gcc安装路径下对应的位置

# 以root账户登录Linux
mkdir /root/template
cd /root/template
# 将三个文件复制到其中
root@yuyi-machine:~/template# ls
freetype_tmp.tar.gz  libfreetype.so.6.18.3  zlib_tmp.tar.gz
# 解压
tar -xzvf freetype_tmp.tar.gz
tar -xzvf zlib_tmp.tar.gz
# 进入你的交叉编译器bin文件夹所在的同级位置, 并记录其位置及目录
cd /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi

------------
root@yuyi-machine:/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi# ls
arm-linux-gnueabi  bin  gcc-linaro-5.4.1-2017.01-linux-manifest.txt  include  lib  libexec  share
-------------
root@yuyi-machine:/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi# pwd
/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi
-------------
root@yuyi-machine:/DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi# cd /root/template #返回前面的解压位置
root@yuyi-machine:~/template# ls
freetype_tmp  freetype_tmp.tar.gz  libfreetype.so.6.18.3  zlib_tmp  zlib_tmp.tar.gz
--------------


#**************将zlib中的头文件和库文件拷贝到交叉编译器下对应的位置
root@yuyi-machine:~/template# cd /root/template/zlib_tmp/include
root@yuyi-machine:~/template/zlib_tmp/include# ls
zconf.h  zlib.h
----------------------
root@yuyi-machine:~/template/zlib_tmp/include# cp * /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/include/ -rf
--------------------
root@yuyi-machine:~/template/zlib_tmp/lib# cd ~/template/zlib_tmp/lib
root@yuyi-machine:~/template/zlib_tmp/lib# cp * /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/lib -rf
---------------------
#**************将freetype中的头文件和库文件拷贝到交叉编译器下对应的位置
root@yuyi-machine:~/template/freetype_tmp/include# cd /root/template/freetype_tmp/include/freetype2/
-----------------
root@yuyi-machine:~/template/freetype_tmp/include/freetype2# ls
freetype  ft2build.h
-------------------
root@yuyi-machine:~/template/freetype_tmp/include/freetype2# cp * /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/include -rf
--------------------
root@yuyi-machine:~/template/freetype_tmp/include/freetype2# cd ~/template/freetype_tmp/lib/
root@yuyi-machine:~/template/freetype_tmp/lib# ls
libfreetype.a  libfreetype.la  libfreetype.so  libfreetype.so.6  libfreetype.so.6.18.3  pkgconfig
root@yuyi-machine:~/template/freetype_tmp/lib# cp * /DevelopmentTool/gcc-linaro-5.4.1-2017.01-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/lib -rf
--------------------

第二步:将freetypetmp/lib/下的libfreetype.so.6.18.3下载到开发板/usr/lib中. (可从Linux服务端下载)

[root@GEC6818 /yuyiworkspace/LVGL]#cd /usr/lib/
[root@GEC6818 /usr/lib]#ls
libEGL.so                  libnl-idiag-3.so
libGLESv2.so               libnl-idiag-3.so.200
libfreetype.so.6.18.3      libnl-idiag-3.so.200.24.0
libnl-3.la                 libnl-nf-3.la
libnl-3.so                 libnl-nf-3.so
libnl-3.so.200             libnl-nf-3.so.200
libnl-3.so.200.24.0        libnl-nf-3.so.200.24.0
libnl-cli-3.la             libnl-route-3.la
libnl-cli-3.so             libnl-route-3.so
libnl-cli-3.so.200         libnl-route-3.so.200
libnl-cli-3.so.200.24.0    libnl-route-3.so.200.24.0
libnl-genl-3.la            libnl-xfrm-3.la
libnl-genl-3.so            libnl-xfrm-3.so
libnl-genl-3.so.200        libnl-xfrm-3.so.200
libnl-genl-3.so.200.24.0   libnl-xfrm-3.so.200.24.0
libnl-idiag-3.la



第三步: 修改

修改LVGL工程的Makefile文件

修改
LDFLAGS ?= -lm -lfreetype

修改LVGL工程中lv_conf.h的第671行

//原本是0
/*FreeType library*/
#define LV_USE_FREETYPE 1
#if LV_USE_FREETYPE

#define LV_FREETYPE_SBIT_CACHE 8*1024//原本是0

第四步: 修改LVGL源码中/lvgl/examples/libs/freetype/lv_example_freetype_1.c 为下面的内容

#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_FREETYPE

/**
 * Load a font with FreeType
 */
void lv_example_freetype_1(void)
{
    /*Create a font*/
    static lv_ft_info_t info;
    /*FreeType uses C standard file system, so no driver letter is required.*/
    // info.name = "./lvgl/examples/libs/freetype/Lato-Regular.ttf";
    info.name = "/fonts/HYZhengYuan55W.ttf"; // TTF文件在开发板上的路径

    info.weight = 24; // 48
    info.style  = FT_FONT_STYLE_NORMAL;
    info.mem    = NULL;
    if(!lv_ft_font_init(&info)) {
        LV_LOG_ERROR("create failed.");
    }

    /*Create style with the new font*/
    static lv_style_t style;
    lv_style_init(&style);
    lv_style_set_text_font(&style, info.font);
    lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER);

    /*Create a label with the new style*/
    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_obj_add_style(label, &style, 0);
    lv_label_set_text(label, "革命尚未成功\n同志仍需努力");
    lv_obj_center(label);
}
#else

void lv_example_freetype_1(void)
{
    /*TODO
     *fallback for online examples*/

    lv_obj_t * label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "FreeType is not installed");
    lv_obj_center(label);
}

#endif
#endif

第五步:把字体文件下载到开发板的/font下面(刚才第四步那个函数写的字体路径就是这个) 要先创建/font文件夹

第六步: 开发板设置

因为在上面编译好的libfreetype.so.6.18.3虽然下载到开发板中的/usr/lib下了,但是因为编译时,其识别的是不带后续次版本和修订号的库libfreetype.so.6。 所以需要在开发板的/usr/lib下将该库添加一个软链接文件或硬链接文件皆可。

开发板命令行中
cd  /usr/lib 
ln    libfreetype.so.6.18.3    libfreetype.so.6    -s  
如果已经有软链接 就不需要再下载了

参考文档

热门相关:间谍的战争   吹神   邪王独爱:娘子不准逃跑   满级绿茶穿到八十年代重新做人   浴火重生:恶魔五小姐