在上一篇博文 U-Boot 之一 零基础编译 U-Boot 过程详解 及 编译后的使用说明 中,最后使用阶段遇到了一些错误,然后发现不能调试(靠打印信息)实在是难受,就开始摸索如何调试 U-Boot,于是就有了这篇博文。
找了一下网上现有的资料,直接使用 GDB 命令行调试是一个选择,但是明显效率不高。于是开始探索直接使用 eclipse 对 U-Boot 进行编译及调试。发现网上有不少说明文章,但大多数都太老旧了,因此我决定重新整理一篇,使用的当前最新的工具环境如下:
- Ubuntu 20.04.3
- Eclipse IDE 2021-12 R Packages Eclipse IDE for Embedded C/C++ Developers
- U-boot 2021.10
- J-Link_Linux_V760b_x86_64.deb
下载安装 eclipse
首先从官网下载最新的针对嵌入式 C/C++ 的 tar 包(现在 eclipse 针对不同开发环境提供了不同的包,我记得之前并没有分开):Eclipse IDE for Embedded C/C++ Developers,地址:https://www./downloads/packages/release/2021-12/r/eclipse-ide-embedded-cc-developers,然后进行安装(解压):  解压之后,我们在 /opt/eclipse/eclipse 目录(我这里先建立了 eclipse 文件夹导致多了一级,大家可以直接解压到 /opt )下直接双击运行 eclipse 程序即可。这里我们直接下载嵌入式专用的版本,主要是出于以下几点:
- 根据官网提示 “The Eclipse Installer 2021‑12 R now includes a JRE for macOS, Windows and Linux.” ,我们不用再安装 Java 运行时 了。解压后直接使用就可以了。
- 包含了一些嵌入式使用的插件(例如 J-Link、OpenOCD 等调试插件 ),这省了我们在去安装这些插件。例如,选择 Eclipse IDE for C/C++ Developers,然后去安装各种插件。
进一步,我们可以选择建立一个 eclipse 的快捷方式,方便后续启动:
- 新建
sudo gedit /usr/share/applications/eclipse.desktop - 输入以下内容:
[Desktop Entry]
Encoding=UTF-8
Name=Eclipse
Comment=Eclipse IDE
Exec=/opt/eclipse/eclipse/eclipse
Icon=/opt/eclipse/eclipse/icon.xpm
Terminal=false
StartupNotify=true
Type=Application
Categories=Application;Development;
- 赋予执行权限
sudo chmod u+x /usr/share/applications/eclipse.desktop - 以上步骤之后我们就可以在桌面最左下角的菜单中找到 eclipse 了。当然还可以在进一步,将
/usr/share/applications/eclipse.desktop 复制到桌面,然后赋予执行权限(应该是还需要右键鼠标,选择 Allow Launching)。
附 tar 命令:
# 压缩
tar -czvf ***.tar.gz
tar -cjvf ***.tar.bz2
# 解压缩
tar -xzvf ***.tar.gz
tar -xjvf ***.tar.bz2
# 参数
-c :建立一个压缩档案的参数指令(create 的意思);
-x :解开一个压缩档案的参数指令!
-t :查看 tarfile 里面的档案!特别注意,在参数的下达中, c/x/t 仅能存在一个!不可同时存在!因为不可能同时压缩与解压缩。
-z :是否同时具有 gzip 的属性,亦即是否需要用 gzip 压缩
-j :是否同时具有 bzip2 的属性,亦即是否需要用 bzip2 压缩
-v :压缩的过程中显示档案!这个常用,但不建议用在背景执行过程!
-f :使用档名。注意,在 f 之后要立即接档名,不要再加参数!例如使用『 tar -zcvfP tfile sfile 』就是错误的写法,要写成『 tar -zcvPf tfile sfile 』才对!
-p :使用原档案的原来属性(属性不会依据使用者而变)
-P :可以使用绝对路径来压缩!
-N :比后面接的日期(yyyy/mm/dd)还要新的才会被打包进新建的档案中!
下载安装 J-Link 驱动
这个就相当简单了,SEGGER 提供了安装包,直接从 https://www./downloads/J-Link/ 下载对应的的 linux 的安装包(例如我的 Ubuntu 对应 64-bit DEB Installer ),然后双击安装就可以了。安装之后默认位置是 ./opt/SEGGER 目录下。  里面的可执行程序都没有对应的桌面图标,运行后在左侧的工具栏上也是黑乎乎的。使用时直接使用命令行或者到目录下双击对应的可执行程序即可。
配置 eclipse
eclipse 的配置分为全局、工作区、项目,优先级前者最低后者最高(后者会覆盖前者)。对于一些通用的配置(例如我们安装的 J-Link 驱动,无论工作区还是项目,应该都用一个),eclipse 推荐直接在全局或者工作区中配置,项目直接继承使用全局或工作区的配置就可以了。 启动 eclipse 会提示选择工作区,默认可以选择不再提示。  启动之后,直接 菜单 --> Window --> Preferences 打开配置界面,我们主要是配置更改 MCU 这个目录(这个好像是由于我们用的嵌入式版 eclipse 自带了 CDT 插件才有这个)下的内容,其他的配置项则根据自己的需要自行修改即可。具体如下:  我这里仅仅配置了编译工具链和 J-Link 的安装位置。之所以这里选择对全局配置项进行配置,主要还是方便在后续建立项目之后,项目自动继承这些配置,方便减少很多操作。
这里再次说明,由于我们选择的是嵌入式专用的 eclipse(Eclipse IDE for Embedded C/C++ Developers ),因此,我们不需要安装 CDT 插件等操作。否则光是配置 eclipse 内容就挺多!
安装 CMSIS-Packs
CMSIS Pack 是 ARM 为 Cortex-M 核定义的一个规范,是一种有效的封装技术,目前支持近 9000 种不同的微控制器。它们为软件组件、设备参数和评估板支持提供了一种交付机制。软件包(文件集合)包括:
- 源代码、头文件和软件库
- 文档和源代码模板
- 设备参数以及启动代码和编程算法
- 示例工程
用过 MDK-ARM(Keil)的应该很熟悉,这个东西不仅可以在 MDK-ARM(Keil)中使用,现在 eclipse、IAR 都集成了 CMSIS Pack,通过 CMSIS Pack 我们可以在线安装一些芯片的包。
这里我们之所以安装 CMSIS Pack(确切的说是安装 CMSIS Pack 中提供的芯片的包),是因为从中我们可以获取到芯片的 SVD 文件,而 SVD 文件中记录了芯片中各种外设的寄存器,在调试时非常有用!如果不使用 SVD 文件,调试器将无法获取芯片中外设的寄存器,只能显示 ARM 核中的几个寄存器。
eclipse 中安装非常简单,但是由于访问的是国外的服务器,速度相当慢(那些包都挺大的),而且经常出现某些芯片下载不下来报错。如果出现报错直接选择忽略即可。具体操作如下图所示:  CMSIS Pack 的安装位置可以在 菜单--> Window-->Preferences --> C/C++ --> MCU Packages 下找到及更改。查看其中的内容,其实就是 Keil 中的那一套东西,因此一种变通的方法是将下载好的内容直接放到上面的目录中即可。SVD 文件就位于 CMSIS-Packs\Keil\STM32F7xx_DFP\2.14.1\CMSIS\SVD 目录下。  注意,上面的这个目录应该是个隐藏文件夹!
编译 U-Boot
新建项目
准备好以上环境及工具之后,就可以直接建立项目了,对于 U-Boot ,我们选择 Makefile Project with Existing Code 。我这里把步骤尽量把步骤合并到一张图,以节约篇幅。具体步骤如下图所示:  其中,我们选择的编译工具链是 Arm Cross GCC。这里的选择主要是让 eclipse 能够主动使用适合我们的一些配置。如果选择其他的,后续也可以再次进行更改(步骤会多一些)。
注意,如果选择在配置章节说的已经在配置了全局或者工作区,下面有些配置其实可以不用更改。我这里就以没有配置来进行演示(覆盖全局配置),对于全局配置有影响的地方单独说明一下。
点击 Finish 之后,默认在选择的源代码目录下新建两个(隐藏)文件:.cproject 和 .project ,这两个就是 eclipse 记录的项目配置信息文件(我之前以为会和 Windows 上的一些软件(例如 vs)似得放到选择的工作区目录下,要不然我选择工作区干啥!)。
项目配置
点击右键菜单最下面的 Properties (也可以通过 菜单 --> Project --> Properties )之后,就打开了项目的配置页面,接下来就是更改一些项目专用的配置了。下面我们一步步说明需要做哪些更改:
-
新增环境变量。具体操作如下图所示:  环境变量下原有的两个 CMD 、PWD 我们不用管它(PATH 变量默认也应该有,不知为何我这里没有)。我们最终需要新增三个环境变量 ARCH 、CROSS_COMPILE 、PATH (如果没有的话),其中, ARCH 和 CROSS_COMPILE 就是我们使用命令行编译时指定的。PATH 主要是告诉 eclipse 我们是用的工具的位置。 这里需要特殊注意 PATH 的值。我们需要先通过上面的 Variables 找到系统 PATH 变量,然后点击 OK,此时,eclipse 就会导入系统环境变量的值。我们需要编辑它,在其中添加我们自己的编译工具链位置(我这里是 /usr/share/gcc-arm-none-eabi-10.3.2021.10/bin ,注意,bin 目录不止一个),否则在编译时会提示找不到相关工具。注意,如果在上面说的全局设置中已经添加了编译器的路径,这里不用再次添加。 最终添加后如下所示:  我们添加的编译器路径用于让 eclipse 找到编译器,其他原有的系统环境变量可以让 eclipse 找到 make 程序。此外,最下面的 Append xxx 这句不要去掉。 -
更改我们使用的编译工具链以及选择使用的芯片。  如果没有配置全局编译器路径,这里必须单独配置;如果设置了这里就会自动读取全局设置的编译工具链,查看一下是否正确即可。如果这里选择了芯片,在调试的时候会省略一些配置。 -
[可选] 不使用 CDT 内建的编译工具链的相关设置(因为我们更换了编译工具链),注意,这里不更换也没啥问题!  -
新增我们自己的编译工具链的头文件路径。每一个编译工具链下都会有 include 文件夹用来存放编译器使用的各种头文件。需要注意的是, include 可能会有好几个,最好都添加上。如果在全局中配置了编译器路径,eclipse 就会自动识别指定的编译工具的相关头文件,这里就可以不用设置。  -
[可选] 开启并行编译。就是指定 make -jn 参数(n 根据处理器来定) 。eclipse 配置如下:  -
[可选] 增加 make stm32f769-disco_defconfig 步骤。完整的构建 U-Boot 的步骤中,第一步是生成 .config 文件,而后是 make menuconfig ,最后才是 make 。如果不添加到 eclipse ,则需要先用命令行执行以上步骤,否则 eclipse 会提示错误。  具体添加如下:  之后,我们就可以在 菜单 --> Project --> Build Targets --> Build 中直接点击上面的配置,执行这一步了。 -
[可选] 修改 make clean 。默认情况下,我们执行 Clean 时,使用是 make clean ,而我们编译 U-Boot 一般使用 make distclean 。这个是 eclipse 默认的设置,我们可以通过如下位置进行修改:  此外,还可以参考第 6 步中新建一个 Build Targets ,只是使用起来没有上面这个方式简单。我第 6 步的图示中已经建立好了!
编译
经过以上步骤,完整的 U-Boot 编译环境就搭建好了,接下来就可以在 eclipse 中构建 U-Boot 了。 
调试 U-Boot
J-Link 连接开发板
调试之前肯定是先把 J-Link 连接到开发板(开发板上有个 20 针脚的 JTAG/SWD 调试接口),确保连接正确。测试连接具体可以使用我们安装的 J-Link 驱动里相应的工具:JFlashExe ,新建一个 STM32F769 芯片的项目,然后连接一下:  提示 Connected successfully 即可。
eclipse 调试相关配置
连接没有问题之后,接下来就是配置 eclipse 了:菜单 --> Run --> Debug Configuration... ,总的来说配置并不麻烦,我这里使用是 J-Link,因此,选择 GDB SEGGER J-link Debugging ,然后点击上面的新建图标(或者直接双击 GDB SEGGER J-link Debugging )就会出现一个新的配置,具体步骤如下图所示:  需要注意的就是选择 C/C++ Application 这一项,我们需要从众多执行程序中选择出我们最终需要 u-boot(这个是最终编译出的带调试信息的,不是 u-boot.bin。具体见博文U-Boot 之三 U-Boot 源码文件解析及移植过程详解)。接下来就是配置界面中剩下的Debugger 、Startup 、Source 、Common 、SVD Path 这 5 个 Tab 页面内容,下面我直接上图来说明每个页面需要的配置:
Main 、Debugger 、Startup  如果已经在全局配置中设置了J-Link 的路径,这里默认是会自动读取全局的配置的 J-Link,不用更改也可以。当然这里再选择一下肯定没有问题。芯片类型如果在构建时选择了芯片,这里也会自动填上选择的芯片。还有就是 Startup --> Setbreakpoint at: 这个默认是 mian,但是 U-Boot 默认没有 main,这里根据实际情况选择。直接 reset ,简单粗暴!还有可以使用 _main 。Source 、Common 、SVD Path  如果按照前面说的安装了 CMSIS-Packs,那么这里就可以找到对应芯片的 SVD 文件,选择 SVD 文件之后,我们在调试时就可以查看外设寄存器的值,否则将无法查看!如下图所示:  注意,eclipse 寄存器分为两部分:Registers 窗口中是 ARM Cortex 核的寄存器(例如,R0、PC),Peripherals 下面就是我们的 SVD 文件中描述的外设寄存器。
U-Boot 调试修改
开启调试选项
默认情况下,U-Boot 的编译已经进行了优化,且默认并不开启调试的,因此我们需要更改一下 U-Boot 的配置。第一个是需要取消 General Setup --> Optimise for size ,在一个就是开启 General Setup --> Configure standard U-Boot features (expert users) -> enable debug information for tools ,具体如下图所示:  这里需要注意,如果使用 make distclean 会清理所有文件,这就会导致以上的配置被清理!所以除非必要,否则还是使用 make clean 好一些。目前来看 make menuconfig 这一步还是需要在终端中执行。
警告:目前我在测试中发现,去掉 General Setup --> Optimise for size 可能导致程序无法运行,暂时没找到解决方法!我目前是在仅开启了 General Setup --> Configure standard U-Boot features (expert users) -> enable debug information for tools 的情况进行调试的。就是偶尔会出现断点位置不正确,不影响正常调试!
这里有个比较严重的问题,去掉 General Setup --> Optimise for size 之后,会导致程序变大,从而原来默认的 SPL 的大小(0x8000)不能容纳实际 SPL 大小,进一步导致了 U-Boot 无法启动。因此,这里我们必须要修改 U-Boot 的基地址。目前,有如下地方需要修改(图里面的 stm32f769-eval 是我移植的,上文暂时还没有更换): 
修改设备树配置
接下来还有个问题:在启动调试之后,调试的程序在调试时只能执行一部分代码,此后就会失败,而且如果不调试想要直接运行是无法直接启动!具体现象如下图所示:  根本原因是由于调试的程序有没有设备树!默认情况下,U-Boot 的可执行程序是 bin 后拼接上 dtb 组成的,而我们调试的程序只有 bin,没有 dtb!解决方法如下有如下两种:
- 将设备树直接编译进 U-Boot 的 bin 文件中,而不是将 设备树单独出来!U-Boot 本身就有这方面的配置,具体如下:
 如果执行过 make distclean 那么每次都需要重新配置上面的选项。 - 在 eclipse 中指定设备树地址。如果使用的是 U-Boot 默认的分离设备树模式,那么在编译成功之后,会在源码的根目录下生成
u-boot.dtb ,这个就是设备数编译之后的文件,而我们可执行程序的结束地址可以从源码的根目录下的 u-boot.map 文件中的 __end 符号找到。  有了 u-boot.dtb 和 __end 之后,我们就可以在 eclipse 中通过命令来解决:  如果 U-Boot 的可执行程序大小有变化,每次都需要更改这里!而且在刚开始启动调试时,eclipse 会报一个错误,稍等一会即可正常进入调试。
经过以上两种方法的任意一种,再次启动调试时,就可以正常执行 board_inti_f 这个函数了!注意,由于这个函数里包含很多接口,执行速度可能有些慢!
重定位配置
接下来的问题就是内存重定位,U-Boot 中存在一段内存重定位的代码,重定位之后将导致调试失败!这主要是因为,在重定位之后,eclipse 正确加载符号表中的各符号。  目前,我还没有找到比较好的解决方法,官网推荐的方法是 使用 gdb 命令行来手动加载符号表 。命令非常简单:add-symbol-file u-boot 重定位后的地址 。重定位后的地址就位于 gd 中的成员变量 unsigned long relocaddr; 中。 
调试
经过上面的配置之后,我们就可以使用 eclipse 对 U-Boot 进行调试了。这里需要注意的是,我们调试的如果是 U-Boot 本身,需要现将 SPL 烧写好,当然我们也可以调试 SPL。启动调试如下图所示: 
参考
- https:///debugging-using-segger-j-link-jtag/
- https://www.cnblogs.com/humaoxiao/p/4166230.html
- https:///blog/2021/09/19/how-to-debug-u-boot/
- https://community./products/devtools/single-board-computers/riotboard/b/blog/posts/automate-uboot-build-with-eclipse
- https:///article/68662419084/
|